diff --git a/framelesshelper.cpp b/framelesshelper.cpp index c0fd8b0..588dca6 100644 --- a/framelesshelper.cpp +++ b/framelesshelper.cpp @@ -54,9 +54,12 @@ FramelessHelper::FramelessHelper(QObject *parent) : QObject(parent) { connect(this, &FramelessHelper::framelessWindowsChanged, [this]() { updateQtFrame_internal(m_titlebarHeight); }); #ifdef Q_OS_WINDOWS - m_borderWidth = WinNativeEventFilter::borderWidth(nullptr); - m_borderHeight = WinNativeEventFilter::borderHeight(nullptr); - m_titlebarHeight = WinNativeEventFilter::titlebarHeight(nullptr); + m_borderWidth = WinNativeEventFilter::getSystemMetric( + nullptr, WinNativeEventFilter::SystemMetric::BorderWidth, false); + m_borderHeight = WinNativeEventFilter::getSystemMetric( + nullptr, WinNativeEventFilter::SystemMetric::BorderHeight, false); + m_titlebarHeight = WinNativeEventFilter::getSystemMetric( + nullptr, WinNativeEventFilter::SystemMetric::TitleBarHeight, false); #else // TODO: The default border width and height on Windows is 8 pixels if DPI // is 96. Don't know how to acquire these values on UNIX platforms. diff --git a/main.cpp b/main.cpp index d4a7579..354007d 100644 --- a/main.cpp +++ b/main.cpp @@ -18,14 +18,11 @@ int main(int argc, char *argv[]) { #endif #endif - QCoreApplication::setAttribute(Qt::AA_DontCreateNativeWidgetSiblings); - QApplication application(argc, argv); FramelessHelper helper; QWidget widget; - widget.setAttribute(Qt::WA_DontCreateNativeAncestors); helper.setFramelessWindows({&widget}); widget.show(); diff --git a/manifest.xml b/manifest.xml index eadb349..86b5003 100644 --- a/manifest.xml +++ b/manifest.xml @@ -26,8 +26,8 @@ - true/pm - PerMonitorV2 + True/PM + PerMonitorV2, PerMonitor true diff --git a/winnativeeventfilter.cpp b/winnativeeventfilter.cpp index f5f71b0..3ad9855 100644 --- a/winnativeeventfilter.cpp +++ b/winnativeeventfilter.cpp @@ -25,11 +25,7 @@ #include "winnativeeventfilter.h" #include -#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)) #include -#else -#include -#endif #include #include #include @@ -105,12 +101,12 @@ #endif #ifndef WM_DPICHANGED -// Only available since Windows 7 +// Only available since Windows 8.1 #define WM_DPICHANGED 0x02E0 #endif #ifndef ABM_GETAUTOHIDEBAREX -// Only available since Windows 8 +// Only available since Windows 8.1 #define ABM_GETAUTOHIDEBAREX 0x0000000b #endif @@ -174,6 +170,12 @@ using APPBARDATA = struct _APPBARDATA { LPARAM lParam; }; +using PROCESS_DPI_AWARENESS = enum _PROCESS_DPI_AWARENESS { + PROCESS_DPI_UNAWARE = 0, + PROCESS_SYSTEM_DPI_AWARE = 1, + PROCESS_PER_MONITOR_DPI_AWARE = 2 +}; + WNEF_GENERATE_WINAPI(GetSystemDpiForProcess, UINT, HANDLE) WNEF_GENERATE_WINAPI(GetDpiForWindow, UINT, HWND) WNEF_GENERATE_WINAPI(GetDpiForSystem, UINT) @@ -232,6 +234,10 @@ WNEF_GENERATE_WINAPI(DeleteObject, BOOL, HGDIOBJ) WNEF_GENERATE_WINAPI(IsThemeActive, BOOL) WNEF_GENERATE_WINAPI(BeginPaint, HDC, HWND, LPPAINTSTRUCT) WNEF_GENERATE_WINAPI(EndPaint, BOOL, HWND, CONST LPPAINTSTRUCT) +WNEF_GENERATE_WINAPI(GetCurrentProcess, HANDLE) +WNEF_GENERATE_WINAPI(GetProcessDpiAwareness, HRESULT, HANDLE, + PROCESS_DPI_AWARENESS *) +WNEF_GENERATE_WINAPI(IsProcessDPIAware, BOOL) BOOL IsDwmCompositionEnabled() { // Since Win8, DWM composition is always enabled and can't be disabled. @@ -347,18 +353,6 @@ void WinNativeEventFilter::clearFramelessWindows() { } } -int WinNativeEventFilter::borderWidth(HWND handle) { - return getBorderWidthForWindow(handle, false); -} - -int WinNativeEventFilter::borderHeight(HWND handle) { - return getBorderHeightForWindow(handle, false); -} - -int WinNativeEventFilter::titlebarHeight(HWND handle) { - return getTitlebarHeightForWindow(handle, false); -} - #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) bool WinNativeEventFilter::nativeEventFilter(const QByteArray &eventType, void *message, qintptr *result) @@ -391,12 +385,15 @@ bool WinNativeEventFilter::nativeEventFilter(const QByteArray &eventType, if (!data->initialized) { // Avoid initializing a same window twice. data->initialized = TRUE; + // Restore default window style. + m_lpSetWindowLongPtrW(msg->hwnd, GWL_STYLE, + WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | + WS_CLIPSIBLINGS); // The following two lines can help us get rid of the three system // buttons (minimize, maximize and close). But they also break the // Arcylic effect (introduced in Win10 1709), don't know why. m_lpSetWindowLongPtrW(msg->hwnd, GWL_EXSTYLE, - m_lpGetWindowLongPtrW(msg->hwnd, GWL_EXSTYLE) | - WS_EX_LAYERED); + WS_EX_APPWINDOW | WS_EX_LAYERED); m_lpSetLayeredWindowAttributes(msg->hwnd, RGB(255, 0, 255), 0, LWA_COLORKEY); // Make sure our window have it's frame shadow. @@ -412,10 +409,13 @@ bool WinNativeEventFilter::nativeEventFilter(const QByteArray &eventType, << getDotsPerInchForWindow(msg->hwnd) << "Window DPR:" << getDevicePixelRatioForWindow(msg->hwnd); - qDebug().noquote() << "Window border width:" << borderWidth(msg->hwnd) - << "Window border height:" << borderHeight(msg->hwnd) - << "Window titlebar height:" - << titlebarHeight(msg->hwnd); + qDebug().noquote() + << "Window border width:" + << getSystemMetric(msg->hwnd, SystemMetric::BorderWidth, false) + << "Window border height:" + << getSystemMetric(msg->hwnd, SystemMetric::BorderHeight, false) + << "Window titlebar height:" + << getSystemMetric(msg->hwnd, SystemMetric::TitleBarHeight, false); #endif } switch (msg->message) { @@ -434,8 +434,10 @@ bool WinNativeEventFilter::nativeEventFilter(const QByteArray &eventType, if (IsMaximized(_hWnd) || IsFullScreened(_hWnd)) { // Windows automatically adds a standard width border to all // sides when a window is maximized. - int frameThickness_x = getBorderWidthForWindow(_hWnd); - int frameThickness_y = getBorderHeightForWindow(_hWnd); + int frameThickness_x = + getSystemMetric(_hWnd, SystemMetric::BorderWidth); + int frameThickness_y = + getSystemMetric(_hWnd, SystemMetric::BorderHeight); // The following two lines are two seperate functions in // Chromium, it uses them to judge whether the window // should draw it's own frame or not. But here we will always @@ -478,30 +480,56 @@ bool WinNativeEventFilter::nativeEventFilter(const QByteArray &eventType, abd.cbSize = sizeof(abd); const UINT taskbarState = m_lpSHAppBarMessage(ABM_GETSTATE, &abd); if (taskbarState & ABS_AUTOHIDE) { - const HMONITOR hMonitor = + const HMONITOR windowMonitor = m_lpMonitorFromWindow(msg->hwnd, MONITOR_DEFAULTTONEAREST); - MONITORINFO monitorInfo; - SecureZeroMemory(&monitorInfo, sizeof(monitorInfo)); - monitorInfo.cbSize = sizeof(monitorInfo); - m_lpGetMonitorInfoW(hMonitor, &monitorInfo); - const auto hasAutohideTaskbar = - [&monitorInfo](const UINT edge) -> bool { + bool top = false, bottom = false, left = false, right = false; + if (QOperatingSystemVersion::current() >= + QOperatingSystemVersion::Windows8_1) { + MONITORINFO monitorInfo; + SecureZeroMemory(&monitorInfo, sizeof(monitorInfo)); + monitorInfo.cbSize = sizeof(monitorInfo); + m_lpGetMonitorInfoW(windowMonitor, &monitorInfo); + const auto hasAutohideTaskbar = + [&monitorInfo](const UINT edge) -> bool { + APPBARDATA _abd; + SecureZeroMemory(&_abd, sizeof(_abd)); + _abd.cbSize = sizeof(_abd); + _abd.uEdge = edge; + _abd.rc = monitorInfo.rcMonitor; + const auto hTaskbar = reinterpret_cast( + m_lpSHAppBarMessage(ABM_GETAUTOHIDEBAREX, &_abd)); + return hTaskbar != nullptr; + }; + top = hasAutohideTaskbar(ABE_TOP); + bottom = hasAutohideTaskbar(ABE_BOTTOM); + left = hasAutohideTaskbar(ABE_LEFT); + right = hasAutohideTaskbar(ABE_RIGHT); + } else { + int edge = -1; APPBARDATA _abd; SecureZeroMemory(&_abd, sizeof(_abd)); _abd.cbSize = sizeof(_abd); - _abd.uEdge = edge; - _abd.rc = monitorInfo.rcMonitor; - const auto hTaskbar = reinterpret_cast( - m_lpSHAppBarMessage(ABM_GETAUTOHIDEBAREX, &_abd)); - return hTaskbar != nullptr; - }; - if (hasAutohideTaskbar(ABE_TOP)) { + _abd.hWnd = m_lpFindWindowW(L"Shell_TrayWnd", nullptr); + if (_abd.hWnd) { + const HMONITOR taskbarMonitor = m_lpMonitorFromWindow( + _abd.hWnd, MONITOR_DEFAULTTOPRIMARY); + if (taskbarMonitor == windowMonitor) { + m_lpSHAppBarMessage(ABM_GETTASKBARPOS, &_abd); + edge = _abd.uEdge; + } + } + top = edge == ABE_TOP; + bottom = edge == ABE_BOTTOM; + left = edge == ABE_LEFT; + right = edge == ABE_RIGHT; + } + if (top) { clientRect->top += kAutoHideTaskbarThicknessPy; - } else if (hasAutohideTaskbar(ABE_BOTTOM)) { + } else if (bottom) { clientRect->bottom -= kAutoHideTaskbarThicknessPy; - } else if (hasAutohideTaskbar(ABE_LEFT)) { + } else if (left) { clientRect->left += kAutoHideTaskbarThicknessPx; - } else if (hasAutohideTaskbar(ABE_RIGHT)) { + } else if (right) { clientRect->right -= kAutoHideTaskbarThicknessPx; } } @@ -578,9 +606,10 @@ bool WinNativeEventFilter::nativeEventFilter(const QByteArray &eventType, mouse.y = GET_Y_LPARAM(_lParam); m_lpScreenToClient(_hWnd, &mouse); // These values are DPI-aware. - const LONG bw = getBorderWidthForWindow(_hWnd); - const LONG bh = getBorderHeightForWindow(_hWnd); - const LONG tbh = getTitlebarHeightForWindow(_hWnd); + const LONG bw = getSystemMetric(_hWnd, SystemMetric::BorderWidth); + const LONG bh = getSystemMetric(_hWnd, SystemMetric::BorderHeight); + const LONG tbh = + getSystemMetric(_hWnd, SystemMetric::TitleBarHeight); const qreal dpr = getDevicePixelRatioForWindow(_hWnd); const bool isTitlebar = (mouse.y < tbh) && !isInSpecificAreas(mouse.x, mouse.y, @@ -765,14 +794,25 @@ UINT WinNativeEventFilter::getDotsPerInchForWindow(HWND handle) { } return defaultValue; }; + bool dpiEnabled = false; + if (m_lpGetProcessDpiAwareness) { + PROCESS_DPI_AWARENESS awareness = PROCESS_DPI_UNAWARE; + m_lpGetProcessDpiAwareness(m_lpGetCurrentProcess(), &awareness); + dpiEnabled = awareness != PROCESS_DPI_UNAWARE; + } else if (m_lpIsProcessDPIAware) { + dpiEnabled = m_lpIsProcessDPIAware(); + } + if (!dpiEnabled) { + // Return hard-coded DPI if DPI scaling is disabled. + return m_defaultDotsPerInch; + } if (!handle) { if (m_lpGetSystemDpiForProcess) { - return m_lpGetSystemDpiForProcess(GetCurrentProcess()); + return m_lpGetSystemDpiForProcess(m_lpGetCurrentProcess()); } else if (m_lpGetDpiForSystem) { return m_lpGetDpiForSystem(); - } else { - return getScreenDpi(m_defaultDotsPerInch); } + return getScreenDpi(m_defaultDotsPerInch); } if (m_lpGetDpiForWindow) { return m_lpGetDpiForWindow(handle); @@ -896,16 +936,20 @@ void WinNativeEventFilter::initWin32Api() { WNEF_RESOLVE_WINAPI(Gdi32, DeleteObject) // Available since Windows XP. WNEF_RESOLVE_WINAPI(Shell32, SHAppBarMessage) + WNEF_RESOLVE_WINAPI(Kernel32, GetCurrentProcess) // Available since Windows Vista. + WNEF_RESOLVE_WINAPI(User32, IsProcessDPIAware) WNEF_RESOLVE_WINAPI(Dwmapi, DwmIsCompositionEnabled) WNEF_RESOLVE_WINAPI(Dwmapi, DwmExtendFrameIntoClientArea) WNEF_RESOLVE_WINAPI(Dwmapi, DwmSetWindowAttribute) WNEF_RESOLVE_WINAPI(UxTheme, IsThemeActive) + // Available since Windows 8.1 if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows8_1) { WNEF_RESOLVE_WINAPI(SHCore, GetDpiForMonitor) + WNEF_RESOLVE_WINAPI(SHCore, GetProcessDpiAwareness) } - // Windows 10, version 1607 (10.0.14393) + // Available since Windows 10, version 1607 (10.0.14393) if (QOperatingSystemVersion::current() >= QOperatingSystemVersion(QOperatingSystemVersion::Windows, 10, 0, 14393)) { @@ -913,7 +957,7 @@ void WinNativeEventFilter::initWin32Api() { WNEF_RESOLVE_WINAPI(User32, GetDpiForSystem) WNEF_RESOLVE_WINAPI(User32, GetSystemMetricsForDpi) } - // Windows 10, version 1803 (10.0.17134) + // Available since Windows 10, version 1803 (10.0.17134) if (QOperatingSystemVersion::current() >= QOperatingSystemVersion(QOperatingSystemVersion::Windows, 10, 0, 17134)) { @@ -1005,7 +1049,8 @@ void WinNativeEventFilter::updateWindow(HWND handle, bool triggerFrameChange) { } } -int WinNativeEventFilter::getBorderWidthForWindow(HWND handle, bool dpiAware) { +int WinNativeEventFilter::getSystemMetric(HWND handle, SystemMetric metric, + bool dpiAware) { initWin32Api(); const qreal dpr = dpiAware ? getDevicePixelRatioForWindow(handle) : m_defaultDevicePixelRatio; @@ -1013,64 +1058,69 @@ int WinNativeEventFilter::getBorderWidthForWindow(HWND handle, bool dpiAware) { createUserData(handle); const auto userData = reinterpret_cast( m_lpGetWindowLongPtrW(handle, GWLP_USERDATA)); - const int bw = userData->windowData.borderWidth; - if (bw > 0) { - return std::round(bw * dpr); + switch (metric) { + case SystemMetric::BorderWidth: { + const int bw = userData->windowData.borderWidth; + if (bw > 0) { + return std::round(bw * dpr); + } + break; + } + case SystemMetric::BorderHeight: { + const int bh = userData->windowData.borderHeight; + if (bh > 0) { + return std::round(bh * dpr); + } + break; + } + case SystemMetric::TitleBarHeight: { + const int tbh = userData->windowData.titlebarHeight; + if (tbh > 0) { + return std::round(tbh * dpr); + } + break; + } } } - if (m_borderWidth > 0) { - return std::round(m_borderWidth * dpr); - } - const int result = m_lpGetSystemMetrics(SM_CXSIZEFRAME) + - m_lpGetSystemMetrics(SM_CXPADDEDBORDER); - const int result_dpi = getSystemMetricsForWindow(handle, SM_CXSIZEFRAME) + - getSystemMetricsForWindow(handle, SM_CXPADDEDBORDER); - return dpiAware ? result_dpi : result; -} - -int WinNativeEventFilter::getBorderHeightForWindow(HWND handle, bool dpiAware) { - initWin32Api(); - const qreal dpr = dpiAware ? getDevicePixelRatioForWindow(handle) - : m_defaultDevicePixelRatio; - if (handle && m_lpIsWindow(handle)) { - createUserData(handle); - const auto userData = reinterpret_cast( - m_lpGetWindowLongPtrW(handle, GWLP_USERDATA)); - const int bh = userData->windowData.borderHeight; - if (bh > 0) { - return std::round(bh * dpr); + switch (metric) { + case SystemMetric::BorderWidth: { + if (m_borderWidth > 0) { + return std::round(m_borderWidth * dpr); + } else { + const int result = m_lpGetSystemMetrics(SM_CXSIZEFRAME) + + m_lpGetSystemMetrics(SM_CXPADDEDBORDER); + const int result_dpi = + getSystemMetricsForWindow(handle, SM_CXSIZEFRAME) + + getSystemMetricsForWindow(handle, SM_CXPADDEDBORDER); + return dpiAware ? result_dpi : result; } } - if (m_borderHeight > 0) { - return std::round(m_borderHeight * dpr); - } - const int result = m_lpGetSystemMetrics(SM_CYSIZEFRAME) + - m_lpGetSystemMetrics(SM_CXPADDEDBORDER); - const int result_dpi = getSystemMetricsForWindow(handle, SM_CYSIZEFRAME) + - getSystemMetricsForWindow(handle, SM_CXPADDEDBORDER); - return dpiAware ? result_dpi : result; -} - -int WinNativeEventFilter::getTitlebarHeightForWindow(HWND handle, - bool dpiAware) { - initWin32Api(); - const qreal dpr = dpiAware ? getDevicePixelRatioForWindow(handle) - : m_defaultDevicePixelRatio; - if (handle && m_lpIsWindow(handle)) { - createUserData(handle); - const auto userData = reinterpret_cast( - m_lpGetWindowLongPtrW(handle, GWLP_USERDATA)); - const int tbh = userData->windowData.titlebarHeight; - if (tbh > 0) { - return std::round(tbh * dpr); + case SystemMetric::BorderHeight: { + if (m_borderHeight > 0) { + return std::round(m_borderHeight * dpr); + } else { + const int result = m_lpGetSystemMetrics(SM_CYSIZEFRAME) + + m_lpGetSystemMetrics(SM_CXPADDEDBORDER); + const int result_dpi = + getSystemMetricsForWindow(handle, SM_CYSIZEFRAME) + + getSystemMetricsForWindow(handle, SM_CXPADDEDBORDER); + return dpiAware ? result_dpi : result; } } - if (m_titlebarHeight > 0) { - return std::round(m_titlebarHeight * dpr); + case SystemMetric::TitleBarHeight: { + if (m_titlebarHeight > 0) { + return std::round(m_titlebarHeight * dpr); + } else { + const int result = m_lpGetSystemMetrics(SM_CYSIZEFRAME) + + m_lpGetSystemMetrics(SM_CXPADDEDBORDER) + + m_lpGetSystemMetrics(SM_CYCAPTION); + const int result_dpi = + getSystemMetricsForWindow(handle, SM_CYSIZEFRAME) + + getSystemMetricsForWindow(handle, SM_CXPADDEDBORDER) + + getSystemMetricsForWindow(handle, SM_CYCAPTION); + return dpiAware ? result_dpi : result; + } } - const int result = getBorderHeightForWindow(handle, false) + - m_lpGetSystemMetrics(SM_CYCAPTION); - const int result_dpi = getBorderHeightForWindow(handle) + - getSystemMetricsForWindow(handle, SM_CYCAPTION); - return dpiAware ? result_dpi : result; + } + return -1; } diff --git a/winnativeeventfilter.h b/winnativeeventfilter.h index d3e5ff7..c916503 100644 --- a/winnativeeventfilter.h +++ b/winnativeeventfilter.h @@ -50,6 +50,8 @@ public: WINDOWDATA windowData; }; + enum class SystemMetric { BorderWidth, BorderHeight, TitleBarHeight }; + explicit WinNativeEventFilter(); ~WinNativeEventFilter() override; @@ -84,15 +86,10 @@ public: static void setBorderHeight(int bh); static void setTitlebarHeight(int tbh); - // DPI-unaware border width 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). - static int borderWidth(HWND handle); - // DPI-unaware border height of the given window (if the pointer is null, - // return the system's standard value). - static int borderHeight(HWND handle); - // DPI-unaware titlebar height (including the border height) of the given - // window (if the pointer is null, return the system's standard value). - static int titlebarHeight(HWND handle); + static int getSystemMetric(HWND handle, SystemMetric metric, + bool dpiAware = true); static void updateWindow(HWND handle, bool triggerFrameChange = true); @@ -112,7 +109,4 @@ private: static UINT getDotsPerInchForWindow(HWND handle); static qreal getDevicePixelRatioForWindow(HWND handle); static int getSystemMetricsForWindow(HWND handle, int index); - static int getBorderWidthForWindow(HWND handle, bool dpiAware = true); - static int getBorderHeightForWindow(HWND handle, bool dpiAware = true); - static int getTitlebarHeightForWindow(HWND handle, bool dpiAware = true); };