parent
8d81a4b34f
commit
e9f71f8d91
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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(¶ms.rgrc[0], &monitorInfo.rcMonitor)) {
|
if (EqualRect(¶ms.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"));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in New Issue