Signed-off-by: Yuhang Zhao <2546789017@qq.com>
This commit is contained in:
Yuhang Zhao 2020-04-07 21:49:01 +08:00
parent 8d81a4b34f
commit e9f71f8d91
3 changed files with 253 additions and 120 deletions

View File

@ -3,10 +3,10 @@ TEMPLATE = app
QT += gui-private widgets QT += gui-private widgets
CONFIG += c++17 strict_c++ utf8_source warn_on CONFIG += c++17 strict_c++ utf8_source warn_on
win32 { win32 {
DEFINES += WIN32_LEAN_AND_MEAN
CONFIG += windeployqt CONFIG += windeployqt
CONFIG -= embed_manifest_exe CONFIG -= embed_manifest_exe
RC_FILE = resources.rc RC_FILE = resources.rc
LIBS += -luser32 -lshell32 -lgdi32 -ldwmapi -luxtheme -ld2d1
HEADERS += winnativeeventfilter.h HEADERS += winnativeeventfilter.h
SOURCES += winnativeeventfilter.cpp SOURCES += winnativeeventfilter.cpp
} }

View File

@ -31,15 +31,42 @@
#include <QTimer> #include <QTimer>
#include <QWindow> #include <QWindow>
#include <QtMath> #include <QtMath>
#include <d2d1.h>
#include <dwmapi.h>
#include <shellapi.h>
#include <uxtheme.h>
#include <windowsx.h> #include <windowsx.h>
// The following constants are necessary for our code but they are not defined #ifndef ABM_GETSTATE
// in MinGW's header files, so we have to define them ourself. The values are // Only available since Windows XP
// taken from MSDN and Windows SDK header files. #define ABM_GETSTATE 0x00000004
#endif
#ifndef ABM_GETTASKBARPOS
// Only available since Windows XP
#define ABM_GETTASKBARPOS 0x00000005
#endif
#ifndef ABS_AUTOHIDE
// Only available since Windows XP
#define ABS_AUTOHIDE 0x0000001
#endif
#ifndef ABE_LEFT
// Only available since Windows XP
#define ABE_LEFT 0
#endif
#ifndef ABE_TOP
// Only available since Windows XP
#define ABE_TOP 1
#endif
#ifndef ABE_RIGHT
// Only available since Windows XP
#define ABE_RIGHT 2
#endif
#ifndef ABE_BOTTOM
// Only available since Windows XP
#define ABE_BOTTOM 3
#endif
#ifndef USER_DEFAULT_SCREEN_DPI #ifndef USER_DEFAULT_SCREEN_DPI
// Only available since Windows Vista // Only available since Windows Vista
@ -51,6 +78,21 @@
#define SM_CXPADDEDBORDER 92 #define SM_CXPADDEDBORDER 92
#endif #endif
#ifndef DWM_BB_ENABLE
// Only available since Windows Vista
#define DWM_BB_ENABLE 0x00000001
#endif
#ifndef WTNCA_NODRAWCAPTION
// Only available since Windows Vista
#define WTNCA_NODRAWCAPTION 0x00000001
#endif
#ifndef WTNCA_NODRAWICON
// Only available since Windows Vista
#define WTNCA_NODRAWICON 0x00000002
#endif
#ifndef WM_NCUAHDRAWCAPTION #ifndef WM_NCUAHDRAWCAPTION
// Not documented, only available since Windows Vista // Not documented, only available since Windows Vista
#define WM_NCUAHDRAWCAPTION 0x00AE #define WM_NCUAHDRAWCAPTION 0x00AE
@ -71,8 +113,26 @@
#define WM_DPICHANGED 0x02E0 #define WM_DPICHANGED 0x02E0
#endif #endif
#ifndef WNEF_RESOLVE_WINAPI
#define WNEF_RESOLVE_WINAPI(libName, funcName) \
if (!m_##funcName) { \
QLibrary library(QString::fromUtf8(#libName)); \
m_##funcName = \
reinterpret_cast<lp##funcName>(library.resolve(#funcName)); \
if (!m_##funcName) { \
qWarning().noquote() \
<< "Failed to resolve" << #funcName << "from" << #libName \
<< "-->" << library.errorString(); \
} \
}
#endif
namespace { namespace {
using WINDOWTHEMEATTRIBUTETYPE = enum _WINDOWTHEMEATTRIBUTETYPE {
WTA_NONCLIENT = 1
};
using WINDOWCOMPOSITIONATTRIB = enum _WINDOWCOMPOSITIONATTRIB { using WINDOWCOMPOSITIONATTRIB = enum _WINDOWCOMPOSITIONATTRIB {
WCA_ACCENT_POLICY = 19 WCA_ACCENT_POLICY = 19
}; };
@ -106,6 +166,40 @@ using MONITOR_DPI_TYPE = enum _MONITOR_DPI_TYPE {
MDT_DEFAULT = MDT_EFFECTIVE_DPI MDT_DEFAULT = MDT_EFFECTIVE_DPI
}; };
using WTA_OPTIONS = struct _WTA_OPTIONS {
DWORD dwFlags;
DWORD dwMask;
};
using DWMNCRENDERINGPOLICY = enum _DWMNCRENDERINGPOLICY { DWMNCRP_ENABLED = 2 };
using DWMWINDOWATTRIBUTE = enum _DWMWINDOWATTRIBUTE {
DWMWA_NCRENDERING_POLICY = 2
};
using DWM_BLURBEHIND = struct _DWM_BLURBEHIND {
DWORD dwFlags;
BOOL fEnable;
HRGN hRgnBlur;
BOOL fTransitionOnMaximized;
};
using MARGINS = struct _MARGINS {
int cxLeftWidth;
int cxRightWidth;
int cyTopHeight;
int cyBottomHeight;
};
using APPBARDATA = struct _APPBARDATA {
DWORD cbSize;
HWND hWnd;
UINT uCallbackMessage;
UINT uEdge;
RECT rc;
LPARAM lParam;
};
using lpGetSystemDpiForProcess = UINT(WINAPI *)(HANDLE); using lpGetSystemDpiForProcess = UINT(WINAPI *)(HANDLE);
lpGetSystemDpiForProcess m_GetSystemDpiForProcess = nullptr; lpGetSystemDpiForProcess m_GetSystemDpiForProcess = nullptr;
@ -123,9 +217,36 @@ using lpGetDpiForMonitor = HRESULT(WINAPI *)(HMONITOR, MONITOR_DPI_TYPE, UINT *,
lpGetDpiForMonitor m_GetDpiForMonitor = nullptr; lpGetDpiForMonitor m_GetDpiForMonitor = nullptr;
using lpSetWindowCompositionAttribute = using lpSetWindowCompositionAttribute =
BOOL(WINAPI *)(HWND, WINDOWCOMPOSITIONATTRIBDATA *); BOOL(WINAPI *)(HWND, const WINDOWCOMPOSITIONATTRIBDATA *);
lpSetWindowCompositionAttribute m_SetWindowCompositionAttribute = nullptr; lpSetWindowCompositionAttribute m_SetWindowCompositionAttribute = nullptr;
using lpSetWindowThemeAttribute = HRESULT(WINAPI *)(HWND,
WINDOWTHEMEATTRIBUTETYPE,
PVOID, DWORD);
lpSetWindowThemeAttribute m_SetWindowThemeAttribute = nullptr;
using lpIsThemeActive = BOOL(WINAPI *)();
lpIsThemeActive m_IsThemeActive = nullptr;
using lpDwmEnableBlurBehindWindow = HRESULT(WINAPI *)(HWND,
const DWM_BLURBEHIND *);
lpDwmEnableBlurBehindWindow m_DwmEnableBlurBehindWindow = nullptr;
using lpDwmExtendFrameIntoClientArea = HRESULT(WINAPI *)(HWND, const MARGINS *);
lpDwmExtendFrameIntoClientArea m_DwmExtendFrameIntoClientArea = nullptr;
using lpDwmIsCompositionEnabled = HRESULT(WINAPI *)(BOOL *);
lpDwmIsCompositionEnabled m_DwmIsCompositionEnabled = nullptr;
using lpDwmSetWindowAttribute = HRESULT(WINAPI *)(HWND, DWORD, LPCVOID, DWORD);
lpDwmSetWindowAttribute m_DwmSetWindowAttribute = nullptr;
using lpSHAppBarMessage = UINT_PTR(WINAPI *)(DWORD, APPBARDATA *);
lpSHAppBarMessage m_SHAppBarMessage = nullptr;
using lpGetDeviceCaps = int(WINAPI *)(HDC, int);
lpGetDeviceCaps m_GetDeviceCaps = nullptr;
const UINT m_defaultDotsPerInch = USER_DEFAULT_SCREEN_DPI; const UINT m_defaultDotsPerInch = USER_DEFAULT_SCREEN_DPI;
const qreal m_defaultDevicePixelRatio = 1.0; const qreal m_defaultDevicePixelRatio = 1.0;
@ -138,7 +259,7 @@ QVector<HWND> m_framelessWindows;
} // namespace } // namespace
WinNativeEventFilter::WinNativeEventFilter() { initDLLs(); } WinNativeEventFilter::WinNativeEventFilter() { initWin32Api(); }
WinNativeEventFilter::~WinNativeEventFilter() = default; WinNativeEventFilter::~WinNativeEventFilter() = default;
@ -173,7 +294,8 @@ void WinNativeEventFilter::setFramelessWindows(QVector<HWND> windows) {
} }
} }
void WinNativeEventFilter::addFramelessWindow(HWND window, WINDOWDATA *data) { void WinNativeEventFilter::addFramelessWindow(HWND window,
const WINDOWDATA *data) {
if (window && !m_framelessWindows.contains(window)) { if (window && !m_framelessWindows.contains(window)) {
m_framelessWindows.append(window); m_framelessWindows.append(window);
if (data) { if (data) {
@ -199,7 +321,7 @@ void WinNativeEventFilter::clearFramelessWindows() {
int WinNativeEventFilter::borderWidth(HWND handle) { int WinNativeEventFilter::borderWidth(HWND handle) {
if (handle) { if (handle) {
createUserData(handle); createUserData(handle);
const auto userData = reinterpret_cast<LPWINDOW>( const auto userData = reinterpret_cast<WINDOW *>(
GetWindowLongPtrW(handle, GWLP_USERDATA)); GetWindowLongPtrW(handle, GWLP_USERDATA));
const int bw = userData->windowData.borderWidth; const int bw = userData->windowData.borderWidth;
if (bw > 0) { if (bw > 0) {
@ -216,7 +338,7 @@ int WinNativeEventFilter::borderWidth(HWND handle) {
int WinNativeEventFilter::borderHeight(HWND handle) { int WinNativeEventFilter::borderHeight(HWND handle) {
if (handle) { if (handle) {
createUserData(handle); createUserData(handle);
const auto userData = reinterpret_cast<LPWINDOW>( const auto userData = reinterpret_cast<WINDOW *>(
GetWindowLongPtrW(handle, GWLP_USERDATA)); GetWindowLongPtrW(handle, GWLP_USERDATA));
const int bh = userData->windowData.borderHeight; const int bh = userData->windowData.borderHeight;
if (bh > 0) { if (bh > 0) {
@ -233,7 +355,7 @@ int WinNativeEventFilter::borderHeight(HWND handle) {
int WinNativeEventFilter::titlebarHeight(HWND handle) { int WinNativeEventFilter::titlebarHeight(HWND handle) {
if (handle) { if (handle) {
createUserData(handle); createUserData(handle);
const auto userData = reinterpret_cast<LPWINDOW>( const auto userData = reinterpret_cast<WINDOW *>(
GetWindowLongPtrW(handle, GWLP_USERDATA)); GetWindowLongPtrW(handle, GWLP_USERDATA));
const int tbh = userData->windowData.titlebarHeight; const int tbh = userData->windowData.titlebarHeight;
if (tbh > 0) { if (tbh > 0) {
@ -283,7 +405,7 @@ bool WinNativeEventFilter::nativeEventFilter(const QByteArray &eventType,
} }
createUserData(msg->hwnd); createUserData(msg->hwnd);
const auto data = const auto data =
reinterpret_cast<LPWINDOW>(GetWindowLongPtrW(msg->hwnd, GWLP_USERDATA)); reinterpret_cast<WINDOW *>(GetWindowLongPtrW(msg->hwnd, GWLP_USERDATA));
// Don't forget to init it if not inited, otherwise the window style will // Don't forget to init it if not inited, otherwise the window style will
// not be updated, but don't init it twice as well. // not be updated, but don't init it twice as well.
if (!data->inited) { if (!data->inited) {
@ -326,32 +448,36 @@ bool WinNativeEventFilter::nativeEventFilter(const QByteArray &eventType,
// the monitor is likely to contain an auto-hide appbar, so // the monitor is likely to contain an auto-hide appbar, so
// the missing client area is covered by it. // the missing client area is covered by it.
if (EqualRect(&params.rgrc[0], &monitorInfo.rcMonitor)) { if (EqualRect(&params.rgrc[0], &monitorInfo.rcMonitor)) {
APPBARDATA abd; if (m_SHAppBarMessage) {
SecureZeroMemory(&abd, sizeof(abd)); APPBARDATA abd;
abd.cbSize = sizeof(abd); SecureZeroMemory(&abd, sizeof(abd));
const UINT taskbarState = abd.cbSize = sizeof(abd);
SHAppBarMessage(ABM_GETSTATE, &abd); const UINT taskbarState =
if (taskbarState & ABS_AUTOHIDE) { m_SHAppBarMessage(ABM_GETSTATE, &abd);
int edge = -1; if (taskbarState & ABS_AUTOHIDE) {
abd.hWnd = FindWindowW(L"Shell_TrayWnd", nullptr); int edge = -1;
if (abd.hWnd) { abd.hWnd =
const HMONITOR taskbarMonitor = FindWindowW(L"Shell_TrayWnd", nullptr);
MonitorFromWindow(abd.hWnd, if (abd.hWnd) {
MONITOR_DEFAULTTONEAREST); const HMONITOR taskbarMonitor =
if (taskbarMonitor && MonitorFromWindow(
(taskbarMonitor == monitor)) { abd.hWnd, MONITOR_DEFAULTTONEAREST);
SHAppBarMessage(ABM_GETTASKBARPOS, &abd); if (taskbarMonitor &&
edge = abd.uEdge; (taskbarMonitor == monitor)) {
m_SHAppBarMessage(ABM_GETTASKBARPOS,
&abd);
edge = abd.uEdge;
}
}
if (edge == ABE_BOTTOM) {
params.rgrc[0].bottom--;
} else if (edge == ABE_LEFT) {
params.rgrc[0].left++;
} else if (edge == ABE_TOP) {
params.rgrc[0].top++;
} else if (edge == ABE_RIGHT) {
params.rgrc[0].right--;
} }
}
if (edge == ABE_BOTTOM) {
params.rgrc[0].bottom--;
} else if (edge == ABE_LEFT) {
params.rgrc[0].left++;
} else if (edge == ABE_TOP) {
params.rgrc[0].top++;
} else if (edge == ABE_RIGHT) {
params.rgrc[0].right--;
} }
} }
} }
@ -405,7 +531,7 @@ bool WinNativeEventFilter::nativeEventFilter(const QByteArray &eventType,
} }
case WM_NCHITTEST: { case WM_NCHITTEST: {
const auto getHTResult = [](HWND _hWnd, LPARAM _lParam, const auto getHTResult = [](HWND _hWnd, LPARAM _lParam,
LPWINDOW _data) -> LRESULT { const WINDOW *_data) -> LRESULT {
const auto isInSpecificAreas = [](int x, int y, const auto isInSpecificAreas = [](int x, int y,
const QVector<QRect> &areas, const QVector<QRect> &areas,
qreal dpr) -> bool { qreal dpr) -> bool {
@ -613,7 +739,7 @@ bool WinNativeEventFilter::nativeEventFilter(const QByteArray &eventType,
return false; return false;
} }
void WinNativeEventFilter::init(LPWINDOW data) { void WinNativeEventFilter::init(WINDOW *data) {
// Make sure we don't init the same window twice. // Make sure we don't init the same window twice.
data->inited = TRUE; data->inited = TRUE;
// Make sure our window is a normal application window, we'll remove the // Make sure our window is a normal application window, we'll remove the
@ -643,9 +769,11 @@ void WinNativeEventFilter::init(LPWINDOW data) {
<< titlebarHeight(data->hWnd); << titlebarHeight(data->hWnd);
} }
void WinNativeEventFilter::handleDwmCompositionChanged(LPWINDOW data) { void WinNativeEventFilter::handleDwmCompositionChanged(WINDOW *data) {
BOOL enabled = FALSE; BOOL enabled = FALSE;
DwmIsCompositionEnabled(&enabled); if (m_DwmIsCompositionEnabled) {
m_DwmIsCompositionEnabled(&enabled);
}
data->dwmCompositionEnabled = enabled; data->dwmCompositionEnabled = enabled;
// We should not draw the frame shadow if DWM composition is disabled, in // We should not draw the frame shadow if DWM composition is disabled, in
// other words, a window should not have frame shadow when Windows Aero is // other words, a window should not have frame shadow when Windows Aero is
@ -653,33 +781,40 @@ void WinNativeEventFilter::handleDwmCompositionChanged(LPWINDOW data) {
// Note that, start from Win8, the DWM composition is always enabled and // Note that, start from Win8, the DWM composition is always enabled and
// can't be disabled. // can't be disabled.
if (enabled) { if (enabled) {
// The frame shadow is drawn on the non-client area and thus we have to if (m_DwmSetWindowAttribute) {
// make sure the non-client area rendering is enabled first. // The frame shadow is drawn on the non-client area and thus we have
const DWMNCRENDERINGPOLICY ncrp = DWMNCRP_ENABLED; // to make sure the non-client area rendering is enabled first.
DwmSetWindowAttribute(data->hWnd, DWMWA_NCRENDERING_POLICY, &ncrp, const DWMNCRENDERINGPOLICY ncrp = DWMNCRP_ENABLED;
sizeof(ncrp)); m_DwmSetWindowAttribute(data->hWnd, DWMWA_NCRENDERING_POLICY, &ncrp,
// Negative margins have special meaning to sizeof(ncrp));
// DwmExtendFrameIntoClientArea. Negative margins create the "sheet of }
// glass" effect, where the client area is rendered as a solid surface if (m_DwmExtendFrameIntoClientArea) {
// with no window border. // Negative margins have special meaning to
const MARGINS margins = {-1, -1, -1, -1}; // DwmExtendFrameIntoClientArea. Negative margins create the "sheet
DwmExtendFrameIntoClientArea(data->hWnd, &margins); // of glass" effect, where the client area is rendered as a solid
// surface with no window border.
const MARGINS margins = {-1, -1, -1, -1};
m_DwmExtendFrameIntoClientArea(data->hWnd, &margins);
}
}
if (m_SetWindowThemeAttribute) {
WTA_OPTIONS options;
options.dwFlags = WTNCA_NODRAWCAPTION | WTNCA_NODRAWICON;
options.dwMask = options.dwFlags;
// This is the official way to hide the window caption text and window
// icon.
m_SetWindowThemeAttribute(data->hWnd, WTA_NONCLIENT, &options,
sizeof(options));
} }
WTA_OPTIONS options;
options.dwFlags = WTNCA_NODRAWCAPTION | WTNCA_NODRAWICON;
options.dwMask = options.dwFlags;
// This is the official way to hide the window caption text and window icon.
SetWindowThemeAttribute(data->hWnd, WTA_NONCLIENT, &options,
sizeof(options));
handleBlurForWindow(data); handleBlurForWindow(data);
refreshWindow(data->hWnd); refreshWindow(data->hWnd);
} }
void WinNativeEventFilter::handleThemeChanged(LPWINDOW data) { void WinNativeEventFilter::handleThemeChanged(WINDOW *data) {
data->themeEnabled = IsThemeActive(); data->themeEnabled = m_IsThemeActive ? m_IsThemeActive() : FALSE;
} }
void WinNativeEventFilter::handleBlurForWindow(LPWINDOW data) { void WinNativeEventFilter::handleBlurForWindow(const WINDOW *data) {
if ((QOperatingSystemVersion::current() < if ((QOperatingSystemVersion::current() <
QOperatingSystemVersion::Windows7) || QOperatingSystemVersion::Windows7) ||
!(data->dwmCompositionEnabled && data->windowData.blurEnabled)) { !(data->dwmCompositionEnabled && data->windowData.blurEnabled)) {
@ -690,13 +825,15 @@ void WinNativeEventFilter::handleBlurForWindow(LPWINDOW data) {
// we won't do it for Vista. // we won't do it for Vista.
if (QOperatingSystemVersion::current() < if (QOperatingSystemVersion::current() <
QOperatingSystemVersion::Windows8) { QOperatingSystemVersion::Windows8) {
// Windows Aero if (m_DwmEnableBlurBehindWindow) {
DWM_BLURBEHIND dwmbb; // Windows Aero
dwmbb.dwFlags = DWM_BB_ENABLE; DWM_BLURBEHIND dwmbb;
dwmbb.fEnable = TRUE; dwmbb.dwFlags = DWM_BB_ENABLE;
dwmbb.hRgnBlur = nullptr; dwmbb.fEnable = TRUE;
dwmbb.fTransitionOnMaximized = FALSE; dwmbb.hRgnBlur = nullptr;
DwmEnableBlurBehindWindow(data->hWnd, &dwmbb); dwmbb.fTransitionOnMaximized = FALSE;
m_DwmEnableBlurBehindWindow(data->hWnd, &dwmbb);
}
} else if (m_SetWindowCompositionAttribute) { } else if (m_SetWindowCompositionAttribute) {
ACCENT_POLICY accentPolicy; ACCENT_POLICY accentPolicy;
accentPolicy.AccentFlags = 0; accentPolicy.AccentFlags = 0;
@ -731,7 +868,8 @@ void WinNativeEventFilter::handleBlurForWindow(LPWINDOW data) {
UINT WinNativeEventFilter::getDotsPerInchForWindow(HWND handle) { UINT WinNativeEventFilter::getDotsPerInchForWindow(HWND handle) {
const auto getScreenDpi = [](UINT defaultValue) -> UINT { const auto getScreenDpi = [](UINT defaultValue) -> UINT {
// Available since Windows 7. #if 0
// Using Direct2D to get screen DPI. Available since Windows 7.
ID2D1Factory *m_pDirect2dFactory = nullptr; ID2D1Factory *m_pDirect2dFactory = nullptr;
if (SUCCEEDED(D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, if (SUCCEEDED(D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED,
&m_pDirect2dFactory)) && &m_pDirect2dFactory)) &&
@ -742,11 +880,12 @@ UINT WinNativeEventFilter::getDotsPerInchForWindow(HWND handle) {
// The values of *dpiX and *dpiY are identical. // The values of *dpiX and *dpiY are identical.
return dpiX; return dpiX;
} }
#endif
// Available since Windows 2000. // Available since Windows 2000.
const HDC hdc = GetDC(nullptr); const HDC hdc = GetDC(nullptr);
if (hdc) { if (hdc && m_GetDeviceCaps) {
const int dpiX = GetDeviceCaps(hdc, LOGPIXELSX); const int dpiX = m_GetDeviceCaps(hdc, LOGPIXELSX);
const int dpiY = GetDeviceCaps(hdc, LOGPIXELSY); const int dpiY = m_GetDeviceCaps(hdc, LOGPIXELSY);
ReleaseDC(nullptr, hdc); ReleaseDC(nullptr, hdc);
// The values of dpiX and dpiY are identical actually, just to // The values of dpiX and dpiY are identical actually, just to
// silence a compiler warning. // silence a compiler warning.
@ -793,7 +932,7 @@ int WinNativeEventFilter::getSystemMetricsForWindow(HWND handle, int index) {
} }
} }
void WinNativeEventFilter::setWindowData(HWND window, WINDOWDATA *data) { void WinNativeEventFilter::setWindowData(HWND window, const WINDOWDATA *data) {
if (window && data) { if (window && data) {
createUserData(window, data); createUserData(window, data);
refreshWindow(window); refreshWindow(window);
@ -804,16 +943,16 @@ WinNativeEventFilter::WINDOWDATA *
WinNativeEventFilter::windowData(HWND window) { WinNativeEventFilter::windowData(HWND window) {
if (window) { if (window) {
createUserData(window); createUserData(window);
return &reinterpret_cast<LPWINDOW>( return &reinterpret_cast<WINDOW *>(
GetWindowLongPtrW(window, GWLP_USERDATA)) GetWindowLongPtrW(window, GWLP_USERDATA))
->windowData; ->windowData;
} }
return nullptr; return nullptr;
} }
void WinNativeEventFilter::createUserData(HWND handle, WINDOWDATA *data) { void WinNativeEventFilter::createUserData(HWND handle, const WINDOWDATA *data) {
if (handle) { if (handle) {
const auto userData = reinterpret_cast<LPWINDOW>( const auto userData = reinterpret_cast<WINDOW *>(
GetWindowLongPtrW(handle, GWLP_USERDATA)); GetWindowLongPtrW(handle, GWLP_USERDATA));
if (userData) { if (userData) {
if (data) { if (data) {
@ -825,7 +964,7 @@ void WinNativeEventFilter::createUserData(HWND handle, WINDOWDATA *data) {
userData->windowData = *data; userData->windowData = *data;
} }
} else { } else {
LPWINDOW _data = new WINDOW; WINDOW *_data = new WINDOW;
_data->hWnd = handle; _data->hWnd = handle;
if (data) { if (data) {
_data->windowData = *data; _data->windowData = *data;
@ -882,51 +1021,39 @@ void WinNativeEventFilter::refreshWindow(HWND handle) {
} }
} }
void WinNativeEventFilter::initDLLs() { void WinNativeEventFilter::initWin32Api() {
QLibrary user32Lib(QString::fromUtf8("User32")), // Available since Windows 2000.
shcoreLib(QString::fromUtf8("SHCore")); WNEF_RESOLVE_WINAPI(Gdi32, GetDeviceCaps)
// Available since Windows XP.
WNEF_RESOLVE_WINAPI(Shell32, SHAppBarMessage)
// Available since Windows Vista.
WNEF_RESOLVE_WINAPI(UxTheme, SetWindowThemeAttribute)
WNEF_RESOLVE_WINAPI(UxTheme, IsThemeActive)
WNEF_RESOLVE_WINAPI(Dwmapi, DwmIsCompositionEnabled)
WNEF_RESOLVE_WINAPI(Dwmapi, DwmExtendFrameIntoClientArea)
WNEF_RESOLVE_WINAPI(Dwmapi, DwmSetWindowAttribute)
WNEF_RESOLVE_WINAPI(Dwmapi, DwmEnableBlurBehindWindow)
if (QOperatingSystemVersion::current() >= if (QOperatingSystemVersion::current() >=
QOperatingSystemVersion::Windows7) { QOperatingSystemVersion::Windows7) {
if (!m_SetWindowCompositionAttribute) { WNEF_RESOLVE_WINAPI(User32, SetWindowCompositionAttribute)
m_SetWindowCompositionAttribute =
reinterpret_cast<lpSetWindowCompositionAttribute>(
user32Lib.resolve("SetWindowCompositionAttribute"));
}
} }
if (QOperatingSystemVersion::current() >= if (QOperatingSystemVersion::current() >=
QOperatingSystemVersion::Windows8_1) { QOperatingSystemVersion::Windows8_1) {
if (!m_GetDpiForMonitor) { WNEF_RESOLVE_WINAPI(SHCore, GetDpiForMonitor)
m_GetDpiForMonitor = reinterpret_cast<lpGetDpiForMonitor>(
shcoreLib.resolve("GetDpiForMonitor"));
}
} }
// Windows 10, version 1607 (10.0.14393) // Windows 10, version 1607 (10.0.14393)
if (QOperatingSystemVersion::current() >= if (QOperatingSystemVersion::current() >=
QOperatingSystemVersion(QOperatingSystemVersion::Windows, 10, 0, QOperatingSystemVersion(QOperatingSystemVersion::Windows, 10, 0,
14393)) { 14393)) {
if (!m_GetDpiForWindow) { WNEF_RESOLVE_WINAPI(User32, GetDpiForWindow)
m_GetDpiForWindow = reinterpret_cast<lpGetDpiForWindow>( WNEF_RESOLVE_WINAPI(User32, GetDpiForSystem)
user32Lib.resolve("GetDpiForWindow")); WNEF_RESOLVE_WINAPI(User32, GetSystemMetricsForDpi)
}
if (!m_GetDpiForSystem) {
m_GetDpiForSystem = reinterpret_cast<lpGetDpiForSystem>(
user32Lib.resolve("GetDpiForSystem"));
}
if (!m_GetSystemMetricsForDpi) {
m_GetSystemMetricsForDpi =
reinterpret_cast<lpGetSystemMetricsForDpi>(
user32Lib.resolve("GetSystemMetricsForDpi"));
}
} }
// Windows 10, version 1803 (10.0.17134) // Windows 10, version 1803 (10.0.17134)
if (QOperatingSystemVersion::current() >= if (QOperatingSystemVersion::current() >=
QOperatingSystemVersion(QOperatingSystemVersion::Windows, 10, 0, QOperatingSystemVersion(QOperatingSystemVersion::Windows, 10, 0,
17134)) { 17134)) {
if (!m_GetSystemDpiForProcess) { WNEF_RESOLVE_WINAPI(User32, GetSystemDpiForProcess)
m_GetSystemDpiForProcess =
reinterpret_cast<lpGetSystemDpiForProcess>(
user32Lib.resolve("GetSystemDpiForProcess"));
}
} }
} }

View File

@ -24,6 +24,10 @@
#pragma once #pragma once
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <QAbstractNativeEventFilter> #include <QAbstractNativeEventFilter>
#include <QRect> #include <QRect>
#include <QVector> #include <QVector>
@ -39,12 +43,13 @@ public:
QVector<QRect> ignoreAreas, draggableAreas; QVector<QRect> ignoreAreas, draggableAreas;
QSize maximumSize = {-1, -1}, minimumSize = {-1, -1}; QSize maximumSize = {-1, -1}, minimumSize = {-1, -1};
}; };
typedef struct tagWINDOW {
using WINDOW = struct _WINDOW {
HWND hWnd = nullptr; HWND hWnd = nullptr;
BOOL dwmCompositionEnabled = FALSE, themeEnabled = FALSE, BOOL dwmCompositionEnabled = FALSE, themeEnabled = FALSE,
inited = FALSE; inited = FALSE;
WINDOWDATA windowData; WINDOWDATA windowData;
} WINDOW, *LPWINDOW; };
explicit WinNativeEventFilter(); explicit WinNativeEventFilter();
~WinNativeEventFilter() override; ~WinNativeEventFilter() override;
@ -58,7 +63,8 @@ public:
static QVector<HWND> framelessWindows(); static QVector<HWND> framelessWindows();
static void setFramelessWindows(QVector<HWND> windows); static void setFramelessWindows(QVector<HWND> windows);
// Make the given window become frameless. // Make the given window become frameless.
static void addFramelessWindow(HWND window, WINDOWDATA *data = nullptr); static void addFramelessWindow(HWND window,
const WINDOWDATA *data = nullptr);
static void removeFramelessWindow(HWND window); static void removeFramelessWindow(HWND window);
static void clearFramelessWindows(); static void clearFramelessWindows();
@ -66,7 +72,7 @@ public:
// restore default behavior. // restore default behavior.
// Note that it can only affect one specific window. // Note that it can only affect one specific window.
// If you want to change these values globally, use setBorderWidth instead. // If you want to change these values globally, use setBorderWidth instead.
static void setWindowData(HWND window, WINDOWDATA *data); static void setWindowData(HWND window, const WINDOWDATA *data);
// You can modify the given window's data directly, it's the same with using // You can modify the given window's data directly, it's the same with using
// setWindowData. // setWindowData.
static WINDOWDATA *windowData(HWND window); static WINDOWDATA *windowData(HWND window);
@ -95,12 +101,12 @@ public:
#endif #endif
private: private:
void init(LPWINDOW data); void init(WINDOW *data);
void initDLLs(); void initWin32Api();
static void createUserData(HWND handle, WINDOWDATA *data = nullptr); static void createUserData(HWND handle, const WINDOWDATA *data = nullptr);
void handleDwmCompositionChanged(LPWINDOW data); void handleDwmCompositionChanged(WINDOW *data);
void handleThemeChanged(LPWINDOW data); void handleThemeChanged(WINDOW *data);
void handleBlurForWindow(LPWINDOW data); void handleBlurForWindow(const WINDOW *data);
static void refreshWindow(HWND handle); static void refreshWindow(HWND handle);
static qreal getPreferedNumber(qreal num); static qreal getPreferedNumber(qreal num);
static UINT getDotsPerInchForWindow(HWND handle); static UINT getDotsPerInchForWindow(HWND handle);