Minor improvements.

1. Use const more.
2. Add some missing ResolveWin32APIs() call
3. Move updateQtFrame to WinNativeEventFilter

Signed-off-by: Yuhang Zhao <2546789017@qq.com>
This commit is contained in:
Yuhang Zhao 2020-05-09 12:58:01 +08:00
parent ae62a8fb49
commit 136b865853
3 changed files with 158 additions and 110 deletions

View File

@ -2,43 +2,17 @@
#include <QApplication> #include <QApplication>
#include <QHBoxLayout> #include <QHBoxLayout>
#include <QLabel> #include <QLabel>
#include <QMargins>
#include <QPushButton> #include <QPushButton>
#ifdef QT_QUICK_LIB #ifdef QT_QUICK_LIB
#include <QQmlContext> #include <QQmlContext>
#include <QQuickItem> #include <QQuickItem>
#include <QQuickView> #include <QQuickView>
#else
#include <QWindow>
#endif #endif
#include <QVBoxLayout> #include <QVBoxLayout>
#include <QWidget> #include <QWidget>
#include <qpa/qplatformnativeinterface.h>
Q_DECLARE_METATYPE(QMargins)
static const int m_defaultTitleBarHeight = 30;
static const int m_defaultButtonWidth = 45; static const int m_defaultButtonWidth = 45;
static void updateQtFrame(QWindow *const window, const int titleBarHeight) {
if (window && (titleBarHeight > 0)) {
// Reduce top frame to zero since we paint it ourselves. Use
// device pixel to avoid rounding errors.
const QMargins margins = {0, -titleBarHeight, 0, 0};
const QVariant marginsVar = QVariant::fromValue(margins);
// The dynamic property takes effect when creating the platform
// window.
window->setProperty("_q_windowsCustomMargins", marginsVar);
// If a platform window exists, change via native interface.
QPlatformWindow *platformWindow = window->handle();
if (platformWindow) {
QGuiApplication::platformNativeInterface()->setWindowProperty(
platformWindow, QString::fromUtf8("WindowsCustomMargins"),
marginsVar);
}
}
}
#ifdef QT_QUICK_LIB #ifdef QT_QUICK_LIB
class MyQuickView : public QQuickView { class MyQuickView : public QQuickView {
Q_OBJECT Q_OBJECT
@ -139,10 +113,6 @@ int main(int argc, char *argv[]) {
data_widget->ignoreObjects << minimizeButton << maximizeButton data_widget->ignoreObjects << minimizeButton << maximizeButton
<< closeButton; << closeButton;
} }
const int tbh_widget = WinNativeEventFilter::getSystemMetric(
hWnd_widget, WinNativeEventFilter::SystemMetric::TitleBarHeight, false);
updateQtFrame(widget.windowHandle(),
(tbh_widget > 0 ? tbh_widget : m_defaultTitleBarHeight));
widget.resize(800, 600); widget.resize(800, 600);
WinNativeEventFilter::moveWindowToDesktopCenter(hWnd_widget); WinNativeEventFilter::moveWindowToDesktopCenter(hWnd_widget);
widget.show(); widget.show();
@ -151,9 +121,8 @@ int main(int argc, char *argv[]) {
// Qt Quick example: // Qt Quick example:
MyQuickView view; MyQuickView view;
const auto hWnd_qml = reinterpret_cast<HWND>(view.winId()); const auto hWnd_qml = reinterpret_cast<HWND>(view.winId());
const int tbh_qml_sys = WinNativeEventFilter::getSystemMetric( const int tbh_qml = WinNativeEventFilter::getSystemMetric(
hWnd_qml, WinNativeEventFilter::SystemMetric::TitleBarHeight, false); hWnd_qml, WinNativeEventFilter::SystemMetric::TitleBarHeight, false);
const int tbh_qml = tbh_qml_sys > 0 ? tbh_qml_sys : m_defaultTitleBarHeight;
view.rootContext()->setContextProperty(QString::fromUtf8("$TitleBarHeight"), view.rootContext()->setContextProperty(QString::fromUtf8("$TitleBarHeight"),
tbh_qml); tbh_qml);
view.setSource(QUrl(QString::fromUtf8("qrc:///qml/main.qml"))); view.setSource(QUrl(QString::fromUtf8("qrc:///qml/main.qml")));
@ -182,7 +151,6 @@ int main(int argc, char *argv[]) {
QObject::connect(rootObject, SIGNAL(closeButtonClicked()), &view, QObject::connect(rootObject, SIGNAL(closeButtonClicked()), &view,
SLOT(close())); SLOT(close()));
WinNativeEventFilter::addFramelessWindow(hWnd_qml); WinNativeEventFilter::addFramelessWindow(hWnd_qml);
updateQtFrame(&view, tbh_qml);
view.resize(800, 600); view.resize(800, 600);
WinNativeEventFilter::moveWindowToDesktopCenter(hWnd_qml); WinNativeEventFilter::moveWindowToDesktopCenter(hWnd_qml);
view.show(); view.show();

View File

@ -27,6 +27,9 @@
#include <QDebug> #include <QDebug>
#include <QGuiApplication> #include <QGuiApplication>
#include <QLibrary> #include <QLibrary>
#include <QMargins>
#include <QWindow>
#include <qpa/qplatformnativeinterface.h>
#if (QT_VERSION >= QT_VERSION_CHECK(5, 9, 0)) #if (QT_VERSION >= QT_VERSION_CHECK(5, 9, 0))
#include <QOperatingSystemVersion> #include <QOperatingSystemVersion>
#else #else
@ -40,6 +43,8 @@
#endif #endif
#include <QtMath> #include <QtMath>
Q_DECLARE_METATYPE(QMargins)
namespace { namespace {
// All the following enums, structs and function prototypes are copied from // All the following enums, structs and function prototypes are copied from
@ -184,6 +189,9 @@ const UINT m_defaultDotsPerInch = USER_DEFAULT_SCREEN_DPI;
const qreal m_defaultDevicePixelRatio = 1.0; const qreal m_defaultDevicePixelRatio = 1.0;
const int m_defaultBorderWidth = 8, m_defaultBorderHeight = 8,
m_defaultTitleBarHeight = 30;
int m_borderWidth = -1, m_borderHeight = -1, m_titleBarHeight = -1; int m_borderWidth = -1, m_borderHeight = -1, m_titleBarHeight = -1;
using HPAINTBUFFER = HANDLE; using HPAINTBUFFER = HANDLE;
@ -491,7 +499,7 @@ BOOL IsDwmCompositionEnabled() {
return SUCCEEDED(m_lpDwmIsCompositionEnabled(&enabled)) && enabled; return SUCCEEDED(m_lpDwmIsCompositionEnabled(&enabled)) && enabled;
} }
WINDOWINFO GetInfoForWindow(HWND handle) { WINDOWINFO GetInfoForWindow(const HWND handle) {
WINDOWINFO windowInfo; WINDOWINFO windowInfo;
SecureZeroMemory(&windowInfo, sizeof(windowInfo)); SecureZeroMemory(&windowInfo, sizeof(windowInfo));
windowInfo.cbSize = sizeof(windowInfo); windowInfo.cbSize = sizeof(windowInfo);
@ -501,7 +509,7 @@ WINDOWINFO GetInfoForWindow(HWND handle) {
return windowInfo; return windowInfo;
} }
MONITORINFO GetMonitorInfoForWindow(HWND handle) { MONITORINFO GetMonitorInfoForWindow(const HWND handle) {
MONITORINFO monitorInfo; MONITORINFO monitorInfo;
SecureZeroMemory(&monitorInfo, sizeof(monitorInfo)); SecureZeroMemory(&monitorInfo, sizeof(monitorInfo));
monitorInfo.cbSize = sizeof(monitorInfo); monitorInfo.cbSize = sizeof(monitorInfo);
@ -515,7 +523,7 @@ MONITORINFO GetMonitorInfoForWindow(HWND handle) {
return monitorInfo; return monitorInfo;
} }
BOOL IsFullScreen(HWND handle) { BOOL IsFullScreen(const HWND handle) {
if (handle && m_lpIsWindow(handle)) { if (handle && m_lpIsWindow(handle)) {
const WINDOWINFO windowInfo = GetInfoForWindow(handle); const WINDOWINFO windowInfo = GetInfoForWindow(handle);
const MONITORINFO monitorInfo = GetMonitorInfoForWindow(handle); const MONITORINFO monitorInfo = GetMonitorInfoForWindow(handle);
@ -528,7 +536,7 @@ BOOL IsFullScreen(HWND handle) {
return FALSE; return FALSE;
} }
BOOL IsTopLevel(HWND handle) { BOOL IsTopLevel(const HWND handle) {
if (handle && m_lpIsWindow(handle)) { if (handle && m_lpIsWindow(handle)) {
if (m_lpGetWindowLongPtrW(handle, GWL_STYLE) & WS_CHILD) { if (m_lpGetWindowLongPtrW(handle, GWL_STYLE) & WS_CHILD) {
return FALSE; return FALSE;
@ -542,8 +550,8 @@ BOOL IsTopLevel(HWND handle) {
return FALSE; return FALSE;
} }
UINT GetDotsPerInchForWindow(HWND handle) { UINT GetDotsPerInchForWindow(const HWND handle) {
const auto getScreenDpi = [](UINT defaultValue) -> UINT { const auto getScreenDpi = [](const UINT defaultValue) -> UINT {
#if 0 #if 0
if (m_lpD2D1CreateFactory) { if (m_lpD2D1CreateFactory) {
// Using Direct2D to get the screen DPI. // Using Direct2D to get the screen DPI.
@ -607,9 +615,9 @@ UINT GetDotsPerInchForWindow(HWND handle) {
return getScreenDpi(m_defaultDotsPerInch); return getScreenDpi(m_defaultDotsPerInch);
} }
qreal GetPreferedNumber(qreal num) { qreal GetPreferedNumber(const qreal num) {
qreal result = -1.0; qreal result = -1.0;
const auto getRoundedNumber = [](qreal in) -> qreal { const auto getRoundedNumber = [](const qreal in) -> qreal {
// If the given number is not very large, we assume it's a // If the given number is not very large, we assume it's a
// device pixel ratio (DPR), otherwise we assume it's a DPI. // device pixel ratio (DPR), otherwise we assume it's a DPI.
if (in < m_defaultDotsPerInch) { if (in < m_defaultDotsPerInch) {
@ -660,7 +668,7 @@ qreal GetPreferedNumber(qreal num) {
return result; return result;
} }
qreal GetDevicePixelRatioForWindow(HWND handle) { qreal GetDevicePixelRatioForWindow(const HWND handle) {
qreal result = m_defaultDevicePixelRatio; qreal result = m_defaultDevicePixelRatio;
if (handle && m_lpIsWindow(handle)) { if (handle && m_lpIsWindow(handle)) {
result = static_cast<qreal>(GetDotsPerInchForWindow(handle)) / result = static_cast<qreal>(GetDotsPerInchForWindow(handle)) /
@ -669,7 +677,8 @@ qreal GetDevicePixelRatioForWindow(HWND handle) {
return GetPreferedNumber(result); return GetPreferedNumber(result);
} }
RECT GetFrameSizeForWindow(HWND handle, bool includingTitleBar = false) { RECT GetFrameSizeForWindow(const HWND handle,
const bool includingTitleBar = false) {
RECT rect = {0, 0, 0, 0}; RECT rect = {0, 0, 0, 0};
if (handle && m_lpIsWindow(handle)) { if (handle && m_lpIsWindow(handle)) {
const auto style = m_lpGetWindowLongPtrW(handle, GWL_STYLE); const auto style = m_lpGetWindowLongPtrW(handle, GWL_STYLE);
@ -703,7 +712,7 @@ RECT GetFrameSizeForWindow(HWND handle, bool includingTitleBar = false) {
return rect; return rect;
} }
void UpdateFrameMarginsForWindow(HWND handle) { void UpdateFrameMarginsForWindow(const HWND handle) {
if (handle && m_lpIsWindow(handle)) { if (handle && m_lpIsWindow(handle)) {
MARGINS margins = {0, 0, 0, 0}; MARGINS margins = {0, 0, 0, 0};
if (IsDwmCompositionEnabled()) { if (IsDwmCompositionEnabled()) {
@ -729,7 +738,7 @@ void UpdateFrameMarginsForWindow(HWND handle) {
} }
} }
int GetSystemMetricsForWindow(HWND handle, int index) { int GetSystemMetricsForWindow(const HWND handle, const int index) {
if (handle && m_lpIsWindow(handle)) { if (handle && m_lpIsWindow(handle)) {
if (m_lpGetSystemMetricsForDpi) { if (m_lpGetSystemMetricsForDpi) {
return m_lpGetSystemMetricsForDpi( return m_lpGetSystemMetricsForDpi(
@ -744,7 +753,7 @@ int GetSystemMetricsForWindow(HWND handle, int index) {
return -1; return -1;
} }
void createUserData(HWND handle, void createUserData(const HWND handle,
const WinNativeEventFilter::WINDOWDATA *data = nullptr) { const WinNativeEventFilter::WINDOWDATA *data = nullptr) {
if (handle && m_lpIsWindow(handle)) { if (handle && m_lpIsWindow(handle)) {
const auto userData = reinterpret_cast<WinNativeEventFilter::WINDOW *>( const auto userData = reinterpret_cast<WinNativeEventFilter::WINDOW *>(
@ -804,26 +813,29 @@ QVector<HWND> WinNativeEventFilter::framelessWindows() {
return m_framelessWindows; return m_framelessWindows;
} }
void WinNativeEventFilter::setFramelessWindows(QVector<HWND> windows) { void WinNativeEventFilter::setFramelessWindows(const QVector<HWND> &windows) {
if (!windows.isEmpty() && (windows != m_framelessWindows)) { if (!windows.isEmpty() && (windows != m_framelessWindows)) {
m_framelessWindows = windows; m_framelessWindows = windows;
for (auto &&window : qAsConst(m_framelessWindows)) { for (auto &&window : qAsConst(m_framelessWindows)) {
createUserData(window); createUserData(window);
updateQtFrame_internal(window);
} }
install(); install();
} }
} }
void WinNativeEventFilter::addFramelessWindow(HWND window, void WinNativeEventFilter::addFramelessWindow(const HWND window,
const WINDOWDATA *data, const WINDOWDATA *data,
bool center, int x, int y, const bool center, const int x,
int width, int height) { const int y, const int width,
const int height) {
ResolveWin32APIs(); ResolveWin32APIs();
if (window && m_lpIsWindow(window) && if (window && m_lpIsWindow(window) &&
!m_framelessWindows.contains(window)) { !m_framelessWindows.contains(window)) {
m_framelessWindows.append(window); m_framelessWindows.append(window);
createUserData(window, data); createUserData(window, data);
install(); install();
updateQtFrame_internal(window);
} }
if ((x > 0) && (y > 0) && (width > 0) && (height > 0)) { if ((x > 0) && (y > 0) && (width > 0) && (height > 0)) {
setWindowGeometry(window, x, y, width, height); setWindowGeometry(window, x, y, width, height);
@ -833,7 +845,7 @@ void WinNativeEventFilter::addFramelessWindow(HWND window,
} }
} }
void WinNativeEventFilter::removeFramelessWindow(HWND window) { void WinNativeEventFilter::removeFramelessWindow(const HWND window) {
if (window && m_framelessWindows.contains(window)) { if (window && m_framelessWindows.contains(window)) {
m_framelessWindows.removeAll(window); m_framelessWindows.removeAll(window);
} }
@ -1242,7 +1254,7 @@ bool WinNativeEventFilter::nativeEventFilter(const QByteArray &eventType,
*result = HTTRANSPARENT; *result = HTTRANSPARENT;
return true; return true;
} }
const auto getHTResult = [](HWND _hWnd, LPARAM _lParam, const auto getHTResult = [](const HWND _hWnd, const LPARAM _lParam,
const WINDOW *_data) -> LRESULT { const WINDOW *_data) -> LRESULT {
const auto isInSpecificAreas = [](const int x, const int y, const auto isInSpecificAreas = [](const int x, const int y,
const QVector<QRect> &areas, const QVector<QRect> &areas,
@ -1407,38 +1419,38 @@ bool WinNativeEventFilter::nativeEventFilter(const QByteArray &eventType,
const MONITORINFO monitorInfo = GetMonitorInfoForWindow(msg->hwnd); const MONITORINFO monitorInfo = GetMonitorInfoForWindow(msg->hwnd);
const RECT rcWorkArea = monitorInfo.rcWork; const RECT rcWorkArea = monitorInfo.rcWork;
const RECT rcMonitorArea = monitorInfo.rcMonitor; const RECT rcMonitorArea = monitorInfo.rcMonitor;
auto &mmi = *reinterpret_cast<LPMINMAXINFO>(msg->lParam); const auto mmi = reinterpret_cast<LPMINMAXINFO>(msg->lParam);
if (isWin8OrGreator()) { if (isWin8OrGreator()) {
// Works fine on Windows 8/8.1/10 // Works fine on Windows 8/8.1/10
mmi.ptMaxPosition.x = mmi->ptMaxPosition.x =
qAbs(rcWorkArea.left - rcMonitorArea.left); qAbs(rcWorkArea.left - rcMonitorArea.left);
mmi.ptMaxPosition.y = qAbs(rcWorkArea.top - rcMonitorArea.top); mmi->ptMaxPosition.y = qAbs(rcWorkArea.top - rcMonitorArea.top);
} else { } else {
// ### FIXME: Buggy on Windows 7: // ### FIXME: Buggy on Windows 7:
// The origin of coordinates is the top left edge of the // The origin of coordinates is the top left edge of the
// monitor's work area. Why? It should be the top left edge of // monitor's work area. Why? It should be the top left edge of
// the monitor's area. // the monitor's area.
mmi.ptMaxPosition.x = rcMonitorArea.left; mmi->ptMaxPosition.x = rcMonitorArea.left;
mmi.ptMaxPosition.y = rcMonitorArea.top; mmi->ptMaxPosition.y = rcMonitorArea.top;
} }
if (data->windowData.maximumSize.isEmpty()) { if (data->windowData.maximumSize.isEmpty()) {
mmi.ptMaxSize.x = qAbs(rcWorkArea.right - rcWorkArea.left); mmi->ptMaxSize.x = qAbs(rcWorkArea.right - rcWorkArea.left);
mmi.ptMaxSize.y = qAbs(rcWorkArea.bottom - rcWorkArea.top); mmi->ptMaxSize.y = qAbs(rcWorkArea.bottom - rcWorkArea.top);
} else { } else {
mmi.ptMaxSize.x = mmi->ptMaxSize.x =
qRound(GetDevicePixelRatioForWindow(msg->hwnd) * qRound(GetDevicePixelRatioForWindow(msg->hwnd) *
data->windowData.maximumSize.width()); data->windowData.maximumSize.width());
mmi.ptMaxSize.y = mmi->ptMaxSize.y =
qRound(GetDevicePixelRatioForWindow(msg->hwnd) * qRound(GetDevicePixelRatioForWindow(msg->hwnd) *
data->windowData.maximumSize.height()); data->windowData.maximumSize.height());
} }
mmi.ptMaxTrackSize.x = mmi.ptMaxSize.x; mmi->ptMaxTrackSize.x = mmi->ptMaxSize.x;
mmi.ptMaxTrackSize.y = mmi.ptMaxSize.y; mmi->ptMaxTrackSize.y = mmi->ptMaxSize.y;
if (!data->windowData.minimumSize.isEmpty()) { if (!data->windowData.minimumSize.isEmpty()) {
mmi.ptMinTrackSize.x = mmi->ptMinTrackSize.x =
qRound(GetDevicePixelRatioForWindow(msg->hwnd) * qRound(GetDevicePixelRatioForWindow(msg->hwnd) *
data->windowData.minimumSize.width()); data->windowData.minimumSize.width());
mmi.ptMinTrackSize.y = mmi->ptMinTrackSize.y =
qRound(GetDevicePixelRatioForWindow(msg->hwnd) * qRound(GetDevicePixelRatioForWindow(msg->hwnd) *
data->windowData.minimumSize.height()); data->windowData.minimumSize.height());
} }
@ -1497,7 +1509,8 @@ bool WinNativeEventFilter::nativeEventFilter(const QByteArray &eventType,
return false; return false;
} }
void WinNativeEventFilter::setWindowData(HWND window, const WINDOWDATA *data) { void WinNativeEventFilter::setWindowData(const HWND window,
const WINDOWDATA *data) {
ResolveWin32APIs(); ResolveWin32APIs();
if (window && m_lpIsWindow(window) && data) { if (window && m_lpIsWindow(window) && data) {
createUserData(window, data); createUserData(window, data);
@ -1505,27 +1518,30 @@ void WinNativeEventFilter::setWindowData(HWND window, const WINDOWDATA *data) {
} }
WinNativeEventFilter::WINDOWDATA * WinNativeEventFilter::WINDOWDATA *
WinNativeEventFilter::windowData(HWND window) { WinNativeEventFilter::windowData(const HWND window) {
ResolveWin32APIs(); ResolveWin32APIs();
if (window && m_lpIsWindow(window)) { if (window && m_lpIsWindow(window)) {
createUserData(window); createUserData(window);
return &reinterpret_cast<WINDOW *>( return &(reinterpret_cast<WINDOW *>(
m_lpGetWindowLongPtrW(window, GWLP_USERDATA)) m_lpGetWindowLongPtrW(window, GWLP_USERDATA))
->windowData; ->windowData);
} }
return nullptr; return nullptr;
} }
void WinNativeEventFilter::setBorderWidth(int bw) { m_borderWidth = bw; } void WinNativeEventFilter::setBorderWidth(const int bw) { m_borderWidth = bw; }
void WinNativeEventFilter::setBorderHeight(int bh) { m_borderHeight = bh; } void WinNativeEventFilter::setBorderHeight(const int bh) {
m_borderHeight = bh;
}
void WinNativeEventFilter::setTitleBarHeight(int tbh) { void WinNativeEventFilter::setTitleBarHeight(const int tbh) {
m_titleBarHeight = tbh; m_titleBarHeight = tbh;
} }
void WinNativeEventFilter::updateWindow(HWND handle, bool triggerFrameChange, void WinNativeEventFilter::updateWindow(const HWND handle,
bool redraw) { const bool triggerFrameChange,
const bool redraw) {
ResolveWin32APIs(); ResolveWin32APIs();
if (handle && m_lpIsWindow(handle)) { if (handle && m_lpIsWindow(handle)) {
if (triggerFrameChange) { if (triggerFrameChange) {
@ -1540,8 +1556,9 @@ void WinNativeEventFilter::updateWindow(HWND handle, bool triggerFrameChange,
} }
} }
int WinNativeEventFilter::getSystemMetric(HWND handle, SystemMetric metric, int WinNativeEventFilter::getSystemMetric(const HWND handle,
bool dpiAware) { const SystemMetric metric,
const bool dpiAware) {
ResolveWin32APIs(); ResolveWin32APIs();
const qreal dpr = dpiAware ? GetDevicePixelRatioForWindow(handle) const qreal dpr = dpiAware ? GetDevicePixelRatioForWindow(handle)
: m_defaultDevicePixelRatio; : m_defaultDevicePixelRatio;
@ -1555,12 +1572,13 @@ int WinNativeEventFilter::getSystemMetric(HWND handle, SystemMetric metric,
if (bw > 0) { if (bw > 0) {
return qRound(bw * dpr); return qRound(bw * dpr);
} else { } else {
const int result = m_lpGetSystemMetrics(SM_CXSIZEFRAME) + const int result_nondpi = m_lpGetSystemMetrics(SM_CXSIZEFRAME) +
m_lpGetSystemMetrics(SM_CXPADDEDBORDER); m_lpGetSystemMetrics(SM_CXPADDEDBORDER);
const int result_dpi = const int result_dpi =
GetSystemMetricsForWindow(handle, SM_CXSIZEFRAME) + GetSystemMetricsForWindow(handle, SM_CXSIZEFRAME) +
GetSystemMetricsForWindow(handle, SM_CXPADDEDBORDER); GetSystemMetricsForWindow(handle, SM_CXPADDEDBORDER);
return dpiAware ? result_dpi : result; const int result = dpiAware ? result_dpi : result_nondpi;
return result > 0 ? result : qRound(m_defaultBorderWidth * dpr);
} }
} }
case SystemMetric::BorderHeight: { case SystemMetric::BorderHeight: {
@ -1568,12 +1586,14 @@ int WinNativeEventFilter::getSystemMetric(HWND handle, SystemMetric metric,
if (bh > 0) { if (bh > 0) {
return qRound(bh * dpr); return qRound(bh * dpr);
} else { } else {
const int result = m_lpGetSystemMetrics(SM_CYSIZEFRAME) + const int result_nondpi = m_lpGetSystemMetrics(SM_CYSIZEFRAME) +
m_lpGetSystemMetrics(SM_CXPADDEDBORDER); m_lpGetSystemMetrics(SM_CXPADDEDBORDER);
const int result_dpi = const int result_dpi =
GetSystemMetricsForWindow(handle, SM_CYSIZEFRAME) + GetSystemMetricsForWindow(handle, SM_CYSIZEFRAME) +
GetSystemMetricsForWindow(handle, SM_CXPADDEDBORDER); GetSystemMetricsForWindow(handle, SM_CXPADDEDBORDER);
return dpiAware ? result_dpi : result; const int result = dpiAware ? result_dpi : result_nondpi;
return result > 0 ? result
: qRound(m_defaultBorderHeight * dpr);
} }
} }
case SystemMetric::TitleBarHeight: { case SystemMetric::TitleBarHeight: {
@ -1581,40 +1601,43 @@ int WinNativeEventFilter::getSystemMetric(HWND handle, SystemMetric metric,
if (tbh > 0) { if (tbh > 0) {
return qRound(tbh * dpr); return qRound(tbh * dpr);
} else { } else {
const int result = m_lpGetSystemMetrics(SM_CYCAPTION); const int result_nondpi = m_lpGetSystemMetrics(SM_CYCAPTION);
const int result_dpi = const int result_dpi =
GetSystemMetricsForWindow(handle, SM_CYCAPTION); GetSystemMetricsForWindow(handle, SM_CYCAPTION);
return dpiAware ? result_dpi : result; const int result = dpiAware ? result_dpi : result_nondpi;
return result > 0 ? result
: qRound(m_defaultTitleBarHeight * dpr);
} }
} }
} }
} }
switch (metric) { switch (metric) {
case SystemMetric::BorderWidth: { case SystemMetric::BorderWidth:
if (m_borderWidth > 0) { if (m_borderWidth > 0) {
return qRound(m_borderWidth * dpr); return qRound(m_borderWidth * dpr);
} else {
return qRound(m_defaultBorderWidth * dpr);
} }
break; case SystemMetric::BorderHeight:
}
case SystemMetric::BorderHeight: {
if (m_borderHeight > 0) { if (m_borderHeight > 0) {
return qRound(m_borderHeight * dpr); return qRound(m_borderHeight * dpr);
} else {
return qRound(m_defaultBorderHeight * dpr);
} }
break; case SystemMetric::TitleBarHeight:
}
case SystemMetric::TitleBarHeight: {
if (m_titleBarHeight > 0) { if (m_titleBarHeight > 0) {
return qRound(m_titleBarHeight * dpr); return qRound(m_titleBarHeight * dpr);
} } else {
break; return qRound(m_defaultTitleBarHeight * dpr);
} }
} }
return -1; return -1;
} }
void WinNativeEventFilter::setWindowGeometry(HWND handle, const int x, void WinNativeEventFilter::setWindowGeometry(const HWND handle, const int x,
const int y, const int width, const int y, const int width,
const int height) { const int height) {
ResolveWin32APIs();
if (handle && m_lpIsWindow(handle) && (x > 0) && (y > 0) && (width > 0) && if (handle && m_lpIsWindow(handle) && (x > 0) && (y > 0) && (width > 0) &&
(height > 0)) { (height > 0)) {
const qreal dpr = GetDevicePixelRatioForWindow(handle); const qreal dpr = GetDevicePixelRatioForWindow(handle);
@ -1627,7 +1650,8 @@ void WinNativeEventFilter::setWindowGeometry(HWND handle, const int x,
} }
} }
void WinNativeEventFilter::moveWindowToDesktopCenter(HWND handle) { void WinNativeEventFilter::moveWindowToDesktopCenter(const HWND handle) {
ResolveWin32APIs();
if (handle && m_lpIsWindow(handle)) { if (handle && m_lpIsWindow(handle)) {
const WINDOWINFO windowInfo = GetInfoForWindow(handle); const WINDOWINFO windowInfo = GetInfoForWindow(handle);
const MONITORINFO monitorInfo = GetMonitorInfoForWindow(handle); const MONITORINFO monitorInfo = GetMonitorInfoForWindow(handle);
@ -1646,3 +1670,46 @@ void WinNativeEventFilter::moveWindowToDesktopCenter(HWND handle) {
ww, wh, TRUE); ww, wh, TRUE);
} }
} }
void WinNativeEventFilter::updateQtFrame(QWindow *const window,
const int titleBarHeight) {
if (window && (titleBarHeight > 0)) {
// Reduce top frame to zero since we paint it ourselves. Use
// device pixel to avoid rounding errors.
const QMargins margins = {0, -titleBarHeight, 0, 0};
const QVariant marginsVar = QVariant::fromValue(margins);
// The dynamic property takes effect when creating the platform
// window.
window->setProperty("_q_windowsCustomMargins", marginsVar);
// If a platform window exists, change via native interface.
QPlatformWindow *platformWindow = window->handle();
if (platformWindow) {
QGuiApplication::platformNativeInterface()->setWindowProperty(
platformWindow, QString::fromUtf8("WindowsCustomMargins"),
marginsVar);
}
}
}
void WinNativeEventFilter::updateQtFrame_internal(const HWND handle) {
ResolveWin32APIs();
if (handle && m_lpIsWindow(handle)) {
const int tbh =
getSystemMetric(handle, SystemMetric::TitleBarHeight, false);
const auto wid = reinterpret_cast<WId>(handle);
#ifdef QT_WIDGETS_LIB
const QWidget *const widget = QWidget::find(wid);
if (widget && widget->isTopLevel()) {
QWindow *const window = widget->windowHandle();
if (window) {
updateQtFrame(window, tbh);
return;
}
}
#endif
QWindow *const window = QWindow::fromWinId(wid);
if (window) {
updateQtFrame(window, tbh);
}
}
}

View File

@ -34,6 +34,10 @@
#include <QVector> #include <QVector>
#include <qt_windows.h> #include <qt_windows.h>
QT_BEGIN_NAMESPACE
QT_FORWARD_DECLARE_CLASS(QWindow)
QT_END_NAMESPACE
#if (QT_VERSION < QT_VERSION_CHECK(5, 13, 0)) #if (QT_VERSION < QT_VERSION_CHECK(5, 13, 0))
#define Q_DISABLE_MOVE(Class) \ #define Q_DISABLE_MOVE(Class) \
Class(Class &&) = delete; \ Class(Class &&) = delete; \
@ -70,53 +74,60 @@ public:
// Frameless windows handle list // Frameless windows handle list
static QVector<HWND> framelessWindows(); static QVector<HWND> framelessWindows();
static void setFramelessWindows(QVector<HWND> windows); static void setFramelessWindows(const QVector<HWND> &windows);
// Make the given window become frameless. // Make the given window become frameless.
// The width and height will be scaled automatically according to DPI. Don't // The width and height will be scaled automatically according to DPI. Don't
// scale them yourself. Just pass the original value. If you don't want to // scale them yourself. Just pass the original value. If you don't want to
// change them, pass negative values to the parameters. // change them, pass negative values to the parameters.
static void addFramelessWindow(HWND window, static void addFramelessWindow(const HWND window,
const WINDOWDATA *data = nullptr, const WINDOWDATA *data = nullptr,
bool center = false, int x = -1, int y = -1, const bool center = false, const int x = -1,
int width = -1, int height = -1); const int y = -1, const int width = -1,
static void removeFramelessWindow(HWND window); const int height = -1);
static void removeFramelessWindow(const HWND window);
static void clearFramelessWindows(); static void clearFramelessWindows();
// Set borderWidth, borderHeight or titleBarHeight to a negative value to // Set borderWidth, borderHeight or titleBarHeight to a negative value to
// 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, const WINDOWDATA *data); static void setWindowData(const 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(const HWND window);
// Change settings globally, not a specific window. // Change settings globally, not a specific window.
// These values will be scaled automatically according to DPI, don't scale // These values will be scaled automatically according to DPI, don't scale
// them yourself. Just pass the original value. // them yourself. Just pass the original value.
static void setBorderWidth(int bw); static void setBorderWidth(const int bw);
static void setBorderHeight(int bh); static void setBorderHeight(const int bh);
static void setTitleBarHeight(int tbh); static void setTitleBarHeight(const int tbh);
// System metric value of the given window (if the pointer is null, // System metric value of the given window (if the pointer is null,
// return the system's standard value). // return the system's standard value).
static int getSystemMetric(HWND handle, SystemMetric metric, static int getSystemMetric(const HWND handle, const SystemMetric metric,
bool dpiAware = true); const bool dpiAware = true);
// Use this function to trigger a frame change event or redraw a // Use this function to trigger a frame change event or redraw a
// specific window. Useful when you want to let some changes // specific window. Useful when you want to let some changes
// in effect immediately. // in effect immediately.
static void updateWindow(HWND handle, bool triggerFrameChange = true, static void updateWindow(const HWND handle,
bool redraw = true); const bool triggerFrameChange = true,
const bool redraw = true);
// Change the geometry of a window through Win32 API. // Change the geometry of a window through Win32 API.
// The width and height will be scaled automatically according to DPI. So // The width and height will be scaled automatically according to DPI. So
// just pass the original value. // just pass the original value.
static void setWindowGeometry(HWND handle, const int x, const int y, static void setWindowGeometry(const HWND handle, const int x, const int y,
const int width, const int height); const int width, const int height);
// Move the window to the center of the desktop. // Move the window to the center of the desktop.
static void moveWindowToDesktopCenter(HWND handle); static void moveWindowToDesktopCenter(const HWND handle);
// Update Qt's internal data about the window frame, otherwise Qt will
// take the size of the window frame into account when anyone is trying to
// change the geometry of the window. That's not what we want.
static void updateQtFrame(QWindow *const window, const int titleBarHeight);
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
bool nativeEventFilter(const QByteArray &eventType, void *message, bool nativeEventFilter(const QByteArray &eventType, void *message,
@ -131,4 +142,6 @@ private:
// will happen. // will happen.
static void install(); static void install();
static void uninstall(); static void uninstall();
static void updateQtFrame_internal(const HWND handle);
}; };