[*] Restore Windows 7 support [pt 2]

Change-Id: Iae61503a4aa2f788fe76b9e9b7a7c1ad1abfae36
This commit is contained in:
Reece Wilson 2023-11-24 02:35:42 +00:00
parent 21ed922bf6
commit 30fa00045e
6 changed files with 238 additions and 59 deletions

View File

@ -63,38 +63,8 @@ QT_BEGIN_NAMESPACE
// Return tablet mode, note: Does not work for GetDesktopWindow().
bool qt_windowsIsTabletMode(HWND hwnd)
{
bool result = false;
const wchar_t uiViewSettingsId[] = L"Windows.UI.ViewManagement.UIViewSettings";
HSTRING_HEADER uiViewSettingsIdRefHeader;
HSTRING uiViewSettingsIdHs = nullptr;
const auto uiViewSettingsIdLen = UINT32(sizeof(uiViewSettingsId) / sizeof(uiViewSettingsId[0]) - 1);
if (FAILED(WindowsCreateStringReference(uiViewSettingsId, uiViewSettingsIdLen, &uiViewSettingsIdRefHeader, &uiViewSettingsIdHs)))
return false;
IUIViewSettingsInterop *uiViewSettingsInterop = nullptr;
// __uuidof(IUIViewSettingsInterop);
const GUID uiViewSettingsInteropRefId = {0x3694dbf9, 0x8f68, 0x44be,{0x8f, 0xf5, 0x19, 0x5c, 0x98, 0xed, 0xe8, 0xa6}};
HRESULT hr = RoGetActivationFactory(uiViewSettingsIdHs, uiViewSettingsInteropRefId,
reinterpret_cast<void **>(&uiViewSettingsInterop));
if (FAILED(hr))
return false;
// __uuidof(ABI::Windows::UI::ViewManagement::IUIViewSettings);
const GUID uiViewSettingsRefId = {0xc63657f6, 0x8850, 0x470d,{0x88, 0xf8, 0x45, 0x5e, 0x16, 0xea, 0x2c, 0x26}};
ABI::Windows::UI::ViewManagement::IUIViewSettings *viewSettings = nullptr;
hr = uiViewSettingsInterop->GetForWindow(hwnd, uiViewSettingsRefId,
reinterpret_cast<void **>(&viewSettings));
if (SUCCEEDED(hr)) {
ABI::Windows::UI::ViewManagement::UserInteractionMode currentMode;
hr = viewSettings->get_UserInteractionMode(&currentMode);
if (SUCCEEDED(hr))
result = currentMode == 1; // Touch, 1
viewSettings->Release();
}
uiViewSettingsInterop->Release();
return result;
return false;
}
QT_END_NAMESPACE

View File

@ -58,6 +58,13 @@
QT_BEGIN_NAMESPACE
typedef HRESULT(__stdcall * SetProcessDpiAwareness_f)(PROCESS_DPI_AWARENESS value);
typedef HRESULT(__stdcall * GetProcessDpiAwareness_f)(HANDLE hprocess, PROCESS_DPI_AWARENESS* value);
typedef BOOL(__stdcall * SetProcessDpiAwarenessContext_f)(DPI_AWARENESS_CONTEXT value);
typedef BOOL(__stdcall * EnableNonClientDpiScaling_f)(HWND hwnd);
typedef DPI_AWARENESS_CONTEXT (__stdcall * GetWindowDpiAwarenessContext_f)(HWND hwnd);
typedef DPI_AWARENESS (__stdcall * GetAwarenessFromDpiAwarenessContext_f)(DPI_AWARENESS_CONTEXT value);
using namespace Qt::StringLiterals;
Q_LOGGING_CATEGORY(lcQpaWindows, "qt.qpa.windows")
@ -119,7 +126,17 @@ static inline bool sessionManagerInteractionBlocked() { return false; }
static inline int windowDpiAwareness(HWND hwnd)
{
return static_cast<int>(GetAwarenessFromDpiAwarenessContext(GetWindowDpiAwarenessContext(hwnd)));
auto pGetAwarenessFromDpiAwarenessContext = reinterpret_cast<GetAwarenessFromDpiAwarenessContext_f>(GetProcAddress(LoadLibraryW(L"USER32.dll"), "GetAwarenessFromDpiAwarenessContext"));
if (!pGetAwarenessFromDpiAwarenessContext) {
return false;
}
auto pGetWindowDpiAwarenessContext = reinterpret_cast<GetWindowDpiAwarenessContext_f>(GetProcAddress(LoadLibraryW(L"USER32.dll"), "GetWindowDpiAwarenessContext"));
if (!pGetWindowDpiAwarenessContext) {
return false;
}
return static_cast<int>(pGetAwarenessFromDpiAwarenessContext(pGetWindowDpiAwarenessContext(hwnd)));
}
// Note: This only works within WM_NCCREATE
@ -127,7 +144,12 @@ static bool enableNonClientDpiScaling(HWND hwnd)
{
bool result = false;
if (windowDpiAwareness(hwnd) == 2) {
result = EnableNonClientDpiScaling(hwnd) != FALSE;
auto pEnableNonClientDpiScaling = reinterpret_cast<EnableNonClientDpiScaling_f>(GetProcAddress(LoadLibraryW(L"USER32.dll"), "EnableNonClientDpiScaling"));
if (!pEnableNonClientDpiScaling) {
return false;
}
result = pEnableNonClientDpiScaling(hwnd) != FALSE;
if (!result) {
const DWORD errorCode = GetLastError();
qErrnoWarning(int(errorCode), "EnableNonClientDpiScaling() failed for HWND %p (%lu)",
@ -364,17 +386,32 @@ void QWindowsContext::setDetectAltGrModifier(bool a)
int QWindowsContext::processDpiAwareness()
{
PROCESS_DPI_AWARENESS result;
if (SUCCEEDED(GetProcessDpiAwareness(nullptr, &result))) {
auto pGetDPIAwareness = reinterpret_cast<GetProcessDpiAwareness_f>(GetProcAddress(LoadLibraryW(L"api-ms-win-shcore-scaling-l1-1-1.dll"), "GetProcessDpiAwareness"));
if (!pGetDPIAwareness) {
return 0;
}
if (SUCCEEDED(pGetDPIAwareness(nullptr, &result))) {
return static_cast<int>(result);
}
return -1;
}
void QWindowsContext::setProcessDpiAwareness(QtWindows::ProcessDpiAwareness dpiAwareness)
{
PROCESS_DPI_AWARENESS result;
auto pSetProcessDpiAwareness = reinterpret_cast<SetProcessDpiAwareness_f>(GetProcAddress(LoadLibraryW(L"api-ms-win-shcore-scaling-l1-1-1.dll"), "SetProcessDpiAwareness"));
if (!pSetProcessDpiAwareness) {
return;
}
qCDebug(lcQpaWindows) << __FUNCTION__ << dpiAwareness;
const HRESULT hr = SetProcessDpiAwareness(static_cast<PROCESS_DPI_AWARENESS>(dpiAwareness));
// E_ACCESSDENIED means set externally (MSVC manifest or external app loading Qt plugin).
const HRESULT hr = pSetProcessDpiAwareness(static_cast<PROCESS_DPI_AWARENESS>(dpiAwareness));
// E_ACCESSDENIED means set externally (MSVC manifest or external app loading Qt plugin).n
// Silence warning in that case unless debug is enabled.
if (FAILED(hr) && (hr != E_ACCESSDENIED || lcQpaWindows().isDebugEnabled())) {
qWarning().noquote().nospace() << "SetProcessDpiAwareness("
@ -384,9 +421,14 @@ void QWindowsContext::setProcessDpiAwareness(QtWindows::ProcessDpiAwareness dpiA
}
bool QWindowsContext::setProcessDpiV2Awareness()
{
{
auto pSetProcessDpiAwarenessContext = reinterpret_cast<SetProcessDpiAwarenessContext_f>(GetProcAddress(LoadLibraryW(L"USER32.dll"), "SetProcessDpiAwarenessContext"));
if (!pSetProcessDpiAwarenessContext) {
return false;
}
qCDebug(lcQpaWindows) << __FUNCTION__;
const BOOL ok = SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
const BOOL ok = pSetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
if (!ok) {
const HRESULT errorCode = GetLastError();
qCWarning(lcQpaWindows).noquote().nospace() << "setProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2) failed: "
@ -910,11 +952,21 @@ void QWindowsContext::forceNcCalcSize(HWND hwnd)
SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOOWNERZORDER);
}
typedef BOOL (__stdcall *SystemParametersInfoForDpi_f)(
UINT uiAction,
UINT uiParam,
PVOID pvParam,
UINT fWinIni,
UINT dpi
);
bool QWindowsContext::systemParametersInfo(unsigned action, unsigned param, void *out,
unsigned dpi)
{
const BOOL result = dpi != 0
? SystemParametersInfoForDpi(action, param, out, 0, dpi)
auto pSystemParametersInfoForDpi = reinterpret_cast<SystemParametersInfoForDpi_f>(GetProcAddress(LoadLibraryW(L"USER32.dll"), "SystemParametersInfoForDpi"));
const BOOL result = dpi != 0 && pSystemParametersInfoForDpi
? pSystemParametersInfoForDpi(action, param, out, 0, dpi)
: SystemParametersInfo(action, param, out, 0);
return result == TRUE;
}

View File

@ -749,17 +749,40 @@ static inline QString messageKeyText(const MSG &msg)
return ch.isNull() ? QString() : QString(ch);
}
UINT GetDpiForWindow2(HWND hwnd);
typedef int (__stdcall *GetSystemMetricsForDpi_f)(int, UINT);
typedef int (__stdcall *GetSystemMetrics_f)(int);
[[nodiscard]] static inline int getTitleBarHeight(const HWND hwnd)
{
const UINT dpi = GetDpiForWindow(hwnd);
const int captionHeight = GetSystemMetricsForDpi(SM_CYCAPTION, dpi);
if (IsZoomed(hwnd))
return captionHeight;
// The frame height should also be taken into account if the window
// is not maximized.
const int frameHeight = GetSystemMetricsForDpi(SM_CYSIZEFRAME, dpi)
+ GetSystemMetricsForDpi(SM_CXPADDEDBORDER, dpi);
return captionHeight + frameHeight;
const UINT dpi = GetDpiForWindow2(hwnd);
auto pGetSystemMetricsForDpi = reinterpret_cast<GetSystemMetricsForDpi_f>(GetProcAddress(LoadLibraryW(L"USER32.dll"), "GetSystemMetricsForDpi"));
auto pGetSystemMetrics = reinterpret_cast<GetSystemMetrics_f>(GetProcAddress(LoadLibraryW(L"USER32.dll"), "GetSystemMetrics"));
if (pGetSystemMetricsForDpi)
{
const int captionHeight = pGetSystemMetricsForDpi(SM_CYCAPTION, dpi);
if (IsZoomed(hwnd))
return captionHeight;
// The frame height should also be taken into account if the window
// is not maximized.
const int frameHeight = pGetSystemMetricsForDpi(SM_CYSIZEFRAME, dpi)
+ pGetSystemMetricsForDpi(SM_CXPADDEDBORDER, dpi);
return captionHeight + frameHeight;
}
else
{
const int captionHeight = pGetSystemMetrics(SM_CYCAPTION);
if (IsZoomed(hwnd))
return captionHeight;
// The frame height should also be taken into account if the window
// is not maximized.
const int frameHeight = pGetSystemMetrics(SM_CYSIZEFRAME)
+ pGetSystemMetrics(SM_CXPADDEDBORDER);
return captionHeight + frameHeight;
}
}
[[nodiscard]] static inline bool isSystemMenuOffsetNeeded(const Qt::WindowFlags flags)

View File

@ -49,6 +49,8 @@ bool QWindowsPointerHandler::translatePointerEvent(QWindow *window, HWND hwnd, Q
{
*result = 0;
const quint32 pointerId = GET_POINTERID_WPARAM(msg.wParam);
#if 0
if (!GetPointerType(pointerId, &m_pointerType)) {
qWarning() << "GetPointerType() failed:" << qt_error_string();
@ -131,6 +133,8 @@ bool QWindowsPointerHandler::translatePointerEvent(QWindow *window, HWND hwnd, Q
return translatePenEvent(window, hwnd, et, msg, &penInfo);
}
}
#endif
return false;
}
@ -558,6 +562,7 @@ QWindowsPointerHandler::QPointingDevicePtr QWindowsPointerHandler::findTabletDev
bool QWindowsPointerHandler::translatePenEvent(QWindow *window, HWND hwnd, QtWindows::WindowsEventType et,
MSG msg, PVOID vPenInfo)
{
#if 0
#if QT_CONFIG(tabletevent)
if (et & QtWindows::NonClientEventFlag)
return false; // Let DefWindowProc() handle Non Client messages.
@ -691,6 +696,8 @@ bool QWindowsPointerHandler::translatePenEvent(QWindow *window, HWND hwnd, QtWin
Q_UNUSED(vPenInfo);
return false;
#endif
#endif
return false;
}
static inline bool isMouseEventSynthesizedFromPenOrTouch()

View File

@ -26,6 +26,11 @@ QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
HRESULT GetDpiForMonitor2(HMONITOR hmonitor,
MONITOR_DPI_TYPE dpiType,
UINT *pDpiX,
UINT *pDpiY);
static inline QDpi deviceDPI(HDC hdc)
{
return QDpi(GetDeviceCaps(hdc, LOGPIXELSX), GetDeviceCaps(hdc, LOGPIXELSY));
@ -35,7 +40,7 @@ static inline QDpi monitorDPI(HMONITOR hMonitor)
{
UINT dpiX;
UINT dpiY;
if (SUCCEEDED(GetDpiForMonitor(hMonitor, MDT_EFFECTIVE_DPI, &dpiX, &dpiY)))
if (SUCCEEDED(GetDpiForMonitor2(hMonitor, MDT_EFFECTIVE_DPI, &dpiX, &dpiY)))
return QDpi(dpiX, dpiY);
return {0, 0};
}
@ -425,6 +430,10 @@ QRect QWindowsScreen::virtualGeometry(const QPlatformScreen *screen) // cf QScre
return result;
}
typedef BOOL (__stdcall *SetDisplayAutoRotationPreferences_f)(
ORIENTATION_PREFERENCE orientation
);
bool QWindowsScreen::setOrientationPreference(Qt::ScreenOrientation o)
{
bool result = false;
@ -444,8 +453,14 @@ bool QWindowsScreen::setOrientationPreference(Qt::ScreenOrientation o)
case Qt::InvertedLandscapeOrientation:
orientationPreference = ORIENTATION_PREFERENCE_LANDSCAPE_FLIPPED;
break;
}
result = SetDisplayAutoRotationPreferences(orientationPreference);
auto pSetDisplayAutoRotationPreferences = reinterpret_cast<SetDisplayAutoRotationPreferences_f>(GetProcAddress(LoadLibraryW(L"user32.dll"), "SetDisplayAutoRotationPreferences"));
if (pSetDisplayAutoRotationPreferences) {
result = pSetDisplayAutoRotationPreferences(orientationPreference);
}
return result;
}

View File

@ -47,6 +47,14 @@
QT_BEGIN_NAMESPACE
typedef int (__stdcall *GetSystemMetricsForDpi_f)(int, UINT);
typedef int (__stdcall *GetSystemMetrics_f)(int);
typedef HRESULT(__stdcall *GetDpiForMonitor_f)(HMONITOR hmonitor,
MONITOR_DPI_TYPE dpiType,
UINT *pDpiX,
UINT *pDpiY);
typedef UINT(__stdcall *GetDpiForWindow_f)(HWND hwnd);
using QWindowCreationContextPtr = QSharedPointer<QWindowCreationContext>;
enum {
@ -518,17 +526,78 @@ static inline void updateGLWindowSettings(const QWindow *w, HWND hwnd, Qt::Windo
[[nodiscard]] static inline int getResizeBorderThickness(const UINT dpi)
{
auto pGetSystemMetricsForDpi = reinterpret_cast<GetSystemMetricsForDpi_f>(GetProcAddress(LoadLibraryW(L"USER32.dll"), "GetSystemMetricsForDpi"));
auto pGetSystemMetrics = reinterpret_cast<GetSystemMetrics_f>(GetProcAddress(LoadLibraryW(L"USER32.dll"), "GetSystemMetrics"));
// The width of the padded border will always be 0 if DWM composition is
// disabled, but since it will always be enabled and can't be programtically
// disabled from Windows 8, we are safe to go.
return GetSystemMetricsForDpi(SM_CXSIZEFRAME, dpi)
+ GetSystemMetricsForDpi(SM_CXPADDEDBORDER, dpi);
if (pGetSystemMetricsForDpi)
{
return pGetSystemMetricsForDpi(SM_CXSIZEFRAME, dpi)
+ pGetSystemMetricsForDpi(SM_CXPADDEDBORDER, dpi);
}
else if (pGetSystemMetrics)
{
return pGetSystemMetrics(SM_CXSIZEFRAME)
+ pGetSystemMetrics(SM_CXPADDEDBORDER);
} else {
return 0;
}
}
/*!
Calculates the dimensions of the invisible borders within the
window frames which only exist on Windows 10 and onwards.
*/
HRESULT GetDpiForMonitor2(HMONITOR hmonitor,
MONITOR_DPI_TYPE dpiType,
UINT *pDpiX,
UINT *pDpiY)
{
auto pGetDpiForMonitor = reinterpret_cast<GetDpiForMonitor_f>(GetProcAddress(LoadLibraryW(L"api-ms-win-shcore-scaling-l1-1-1.dll"), "GetDpiForMonitor"));
if (pGetDpiForMonitor)
{
return pGetDpiForMonitor(hmonitor, dpiType, pDpiX, pDpiY);
}
auto hwnd = GetActiveWindow();
if (HDC hDC = GetDC(hwnd))
{
auto dpiX = GetDeviceCaps(hDC, LOGPIXELSX);
auto dpiY = GetDeviceCaps(hDC, LOGPIXELSY);
ReleaseDC(hwnd, hDC);
*pDpiX = dpiX;
*pDpiY = dpiY;
return S_OK;
}
else
{
*pDpiX = 97;
*pDpiY = 97;
return S_OK;
}
}
UINT GetDpiForWindow2(HWND hwnd)
{
auto pGetDpiForWindow = reinterpret_cast<GetDpiForWindow_f>(GetProcAddress(LoadLibraryW(L"USER32.dll"), "GetDpiForWindow"));
if (pGetDpiForWindow) {
return pGetDpiForWindow(hwnd);
}
if (HDC hDC = GetDC(hwnd))
{
return GetDeviceCaps(hDC, LOGPIXELSX);
}
else
{
return 97;
}
}
static QMargins invisibleMargins(QPoint screenPoint)
{
@ -536,7 +605,7 @@ static QMargins invisibleMargins(QPoint screenPoint)
if (HMONITOR hMonitor = MonitorFromPoint(pt, MONITOR_DEFAULTTONULL)) {
UINT dpiX;
UINT dpiY;
if (SUCCEEDED(GetDpiForMonitor(hMonitor, MDT_EFFECTIVE_DPI, &dpiX, &dpiY))) {
if (SUCCEEDED(GetDpiForMonitor2(hMonitor, MDT_EFFECTIVE_DPI, &dpiX, &dpiY))) {
const int gap = getResizeBorderThickness(dpiX);
return QMargins(gap, 0, gap, gap);
}
@ -546,7 +615,7 @@ static QMargins invisibleMargins(QPoint screenPoint)
[[nodiscard]] static inline QMargins invisibleMargins(const HWND hwnd)
{
const UINT dpi = GetDpiForWindow(hwnd);
const UINT dpi = GetDpiForWindow2(hwnd);
const int gap = getResizeBorderThickness(dpi);
return QMargins(gap, 0, gap, gap);
}
@ -1024,6 +1093,49 @@ static QSize toNativeSizeConstrained(QSize dip, const QScreen *s)
\internal
*/
typedef BOOL (__stdcall *AdjustWindowRectExForDpi_f)(
LPRECT lpRect,
DWORD dwStyle,
BOOL bMenu,
DWORD dwExStyle,
UINT dpi
);
typedef BOOL (__stdcall *AdjustWindowRectEx_f)(
LPRECT lpRect,
DWORD dwStyle,
BOOL bMenu,
DWORD dwExStyle
);
static BOOL AdjustWindowRectExForDpi2(LPRECT lpRect,
DWORD dwStyle,
BOOL bMenu,
DWORD dwExStyle,
UINT dpi
)
{
auto pAdjustWindowRectExForDpi = reinterpret_cast<AdjustWindowRectExForDpi_f>(GetProcAddress(LoadLibraryW(L"user32.dll"), "AdjustWindowRectExForDpi"));
if (pAdjustWindowRectExForDpi) {
return pAdjustWindowRectExForDpi(lpRect,
dwStyle,
bMenu,
dwExStyle,
dpi);
}
auto pAdjustWindowRectEx = reinterpret_cast<AdjustWindowRectEx_f>(GetProcAddress(LoadLibraryW(L"user32.dll"), "AdjustWindowRectEx"));
if (pAdjustWindowRectEx) {
return pAdjustWindowRectEx(lpRect,
dwStyle,
bMenu,
dwExStyle);
}
return 0;
}
QMargins QWindowsGeometryHint::frameOnPrimaryScreen(const QWindow *w, DWORD style, DWORD exStyle)
{
if (!w->isTopLevel() || w->flags().testFlag(Qt::FramelessWindowHint))
@ -1054,7 +1166,7 @@ QMargins QWindowsGeometryHint::frame(const QWindow *w, DWORD style, DWORD exStyl
return {};
RECT rect = {0,0,0,0};
style &= ~DWORD(WS_OVERLAPPED); // Not permitted, see docs.
if (AdjustWindowRectExForDpi(&rect, style, FALSE, exStyle, unsigned(qRound(dpi))) == FALSE) {
if (AdjustWindowRectExForDpi2(&rect, style, FALSE, exStyle, unsigned(qRound(dpi))) == FALSE) {
qErrnoWarning("%s: AdjustWindowRectExForDpi failed", __FUNCTION__);
}
const QMargins result(qAbs(rect.left), qAbs(rect.top),
@ -1545,7 +1657,7 @@ void QWindowsWindow::initialize()
QWindowSystemInterface::handleGeometryChange<QWindowSystemInterface::SynchronousDelivery>(w, obtainedGeometry);
}
}
QWindowsWindow::setSavedDpi(GetDpiForWindow(handle()));
QWindowsWindow::setSavedDpi(GetDpiForWindow2(handle()));
}
QSurfaceFormat QWindowsWindow::format() const
@ -2011,7 +2123,7 @@ void QWindowsWindow::handleDpiChanged(HWND hwnd, WPARAM wParam, LPARAM lParam)
void QWindowsWindow::handleDpiChangedAfterParent(HWND hwnd)
{
const UINT dpi = GetDpiForWindow(hwnd);
const UINT dpi = GetDpiForWindow2(hwnd);
const qreal scale = qreal(dpi) / qreal(savedDpi());
setSavedDpi(dpi);