diff --git a/README.md b/README.md index 70d84db9..4735a8d0 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -This is Qt 6.6.1 backport that runs on Windows 7 (what?). The repository is the qtbase module source code with all required modifications already applied. +This is Qt 6.6.1 backport that runs on Windows 7 (what?). The repository contains patched source files from the qtbase module. Approach is based on this [forum thread](https://forum.qt.io/topic/133002/qt-creator-6-0-1-and-qt-6-2-2-running-on-windows-7/60) but better: many improvements amongst important fallbacks to default Qt 6 behaviour when running on newer Windows. You can use [our prebuild binaries](https://github.com/crystalidea/qt6windows7/releases) (we used Visual C++ 2019 with OpenSSL 1.1.1k statically linked, see [compile_win.pl](https://github.com/crystalidea/qt-build-tools/tree/master/6.6.1) script) or compile Qt yourself. diff --git a/qtbase/src/corelib/io/qstandardpaths_win.cpp b/qtbase/src/corelib/io/qstandardpaths_win.cpp index 13b8fe22..9e2607c3 100644 --- a/qtbase/src/corelib/io/qstandardpaths_win.cpp +++ b/qtbase/src/corelib/io/qstandardpaths_win.cpp @@ -12,6 +12,7 @@ #include #include +#include #include #include @@ -60,20 +61,26 @@ static inline void appendTestMode(QString &path) static bool isProcessLowIntegrity() { + if (!IsWindows8OrGreater()) + return false; + // same as GetCurrentProcessToken() const auto process_token = HANDLE(quintptr(-4)); QVarLengthArray token_info_buf(256); auto* token_info = reinterpret_cast(token_info_buf.data()); DWORD token_info_length = token_info_buf.size(); - if (!GetTokenInformation(process_token, TokenIntegrityLevel, token_info, token_info_length, &token_info_length)) { + if (!GetTokenInformation(process_token, TokenIntegrityLevel, token_info, token_info_length, &token_info_length) + && GetLastError() == ERROR_INSUFFICIENT_BUFFER) { // grow buffer and retry GetTokenInformation token_info_buf.resize(token_info_length); token_info = reinterpret_cast(token_info_buf.data()); if (!GetTokenInformation(process_token, TokenIntegrityLevel, token_info, token_info_length, &token_info_length)) return false; // assume "normal" process } - + else + return false; + // The GetSidSubAuthorityCount return-code is undefined on failure, so // there's no point in checking before dereferencing DWORD integrity_level = *GetSidSubAuthority(token_info->Label.Sid, *GetSidSubAuthorityCount(token_info->Label.Sid) - 1); diff --git a/qtbase/src/corelib/kernel/qeventdispatcher_win.cpp b/qtbase/src/corelib/kernel/qeventdispatcher_win.cpp index f7fd2a7b..30ea3bfe 100644 --- a/qtbase/src/corelib/kernel/qeventdispatcher_win.cpp +++ b/qtbase/src/corelib/kernel/qeventdispatcher_win.cpp @@ -361,10 +361,15 @@ void QEventDispatcherWin32Private::registerTimer(WinTimerInfo *t) ok = t->fastTimerId; } - if (!ok) { + typedef BOOL (WINAPI *SetCoalescableTimerFunc) (HWND, UINT_PTR, UINT, TIMERPROC, ULONG); + static SetCoalescableTimerFunc mySetCoalescableTimerFunc = + (SetCoalescableTimerFunc)::GetProcAddress(::GetModuleHandle(L"User32"), "SetCoalescableTimer"); + + if (!ok && mySetCoalescableTimerFunc) { // user normal timers for (Very)CoarseTimers, or if no more multimedia timers available - ok = SetCoalescableTimer(internalHwnd, t->timerId, interval, nullptr, tolerance); + ok = mySetCoalescableTimerFunc(internalHwnd, t->timerId, interval, nullptr, tolerance); } + if (!ok) ok = SetTimer(internalHwnd, t->timerId, interval, nullptr); diff --git a/qtbase/src/corelib/kernel/qfunctions_win.cpp b/qtbase/src/corelib/kernel/qfunctions_win.cpp index d5ce3e58..70b67ea0 100644 --- a/qtbase/src/corelib/kernel/qfunctions_win.cpp +++ b/qtbase/src/corelib/kernel/qfunctions_win.cpp @@ -43,23 +43,33 @@ QComHelper::~QComHelper() */ bool qt_win_hasPackageIdentity() { + typedef BOOL (WINAPI *GetCurrentPackageFullNameFunc) (UINT32 *, PWSTR); + static GetCurrentPackageFullNameFunc myGetCurrentPackageFullName = + (GetCurrentPackageFullNameFunc)::GetProcAddress(::GetModuleHandle(L"kernel32"), "GetCurrentPackageFullName"); + + if (myGetCurrentPackageFullName) + { #if defined(HAS_APPMODEL) - static const bool hasPackageIdentity = []() { - UINT32 length = 0; - switch (const auto result = GetCurrentPackageFullName(&length, nullptr)) { - case ERROR_INSUFFICIENT_BUFFER: - return true; - case APPMODEL_ERROR_NO_PACKAGE: - return false; - default: - qWarning("Failed to resolve package identity (error code %ld)", result); - return false; - } - }(); - return hasPackageIdentity; + + static const bool hasPackageIdentity = []() { + UINT32 length = 0; + switch (const auto result = myGetCurrentPackageFullName(&length, nullptr)) { + case ERROR_INSUFFICIENT_BUFFER: + return true; + case APPMODEL_ERROR_NO_PACKAGE: + return false; + default: + qWarning("Failed to resolve package identity (error code %ld)", result); + return false; + } + }(); + return hasPackageIdentity; #else - return false; + return false; #endif + } + + return false; } QT_END_NAMESPACE diff --git a/qtbase/src/corelib/thread/qfutex_p.h b/qtbase/src/corelib/thread/qfutex_p.h index 48f03f5e..efb14851 100644 --- a/qtbase/src/corelib/thread/qfutex_p.h +++ b/qtbase/src/corelib/thread/qfutex_p.h @@ -107,39 +107,6 @@ namespace QtLinuxFutex { } namespace QtFutex = QtLinuxFutex; QT_END_NAMESPACE - -#elif defined(Q_OS_WIN) -# include - -QT_BEGIN_NAMESPACE -namespace QtWindowsFutex { -#define QT_ALWAYS_USE_FUTEX -constexpr inline bool futexAvailable() { return true; } - -template -inline void futexWait(Atomic &futex, typename Atomic::Type expectedValue) -{ - QtTsan::futexRelease(&futex); - WaitOnAddress(&futex, &expectedValue, sizeof(expectedValue), INFINITE); - QtTsan::futexAcquire(&futex); -} -template -inline bool futexWait(Atomic &futex, typename Atomic::Type expectedValue, qint64 nstimeout) -{ - BOOL r = WaitOnAddress(&futex, &expectedValue, sizeof(expectedValue), DWORD(nstimeout / 1000 / 1000)); - return r || GetLastError() != ERROR_TIMEOUT; -} -template inline void futexWakeAll(Atomic &futex) -{ - WakeByAddressAll(&futex); -} -template inline void futexWakeOne(Atomic &futex) -{ - WakeByAddressSingle(&futex); -} -} -namespace QtFutex = QtWindowsFutex; -QT_END_NAMESPACE #else QT_BEGIN_NAMESPACE diff --git a/qtbase/src/corelib/thread/qmutex.cpp b/qtbase/src/corelib/thread/qmutex.cpp index b794d79e..0e941218 100644 --- a/qtbase/src/corelib/thread/qmutex.cpp +++ b/qtbase/src/corelib/thread/qmutex.cpp @@ -915,8 +915,10 @@ QT_END_NAMESPACE #if defined(QT_ALWAYS_USE_FUTEX) // nothing -#elif defined(Q_OS_DARWIN) +#elif defined(Q_OS_MAC) # include "qmutex_mac.cpp" +#elif defined(Q_OS_WIN) +# include "qmutex_win.cpp" #else # include "qmutex_unix.cpp" -#endif +#endif \ No newline at end of file diff --git a/qtbase/src/corelib/thread/qmutex_p.h b/qtbase/src/corelib/thread/qmutex_p.h index aabb66fa..a16d5082 100644 --- a/qtbase/src/corelib/thread/qmutex_p.h +++ b/qtbase/src/corelib/thread/qmutex_p.h @@ -86,6 +86,8 @@ public: semaphore_t mach_semaphore; #elif defined(Q_OS_UNIX) sem_t semaphore; +#elif defined(Q_OS_WIN) + Qt::HANDLE event; #endif }; diff --git a/qtbase/src/corelib/thread/qmutex_win.cpp b/qtbase/src/corelib/thread/qmutex_win.cpp new file mode 100644 index 00000000..9186f89a --- /dev/null +++ b/qtbase/src/corelib/thread/qmutex_win.cpp @@ -0,0 +1,30 @@ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#include "qmutex.h" +#include +#include "qmutex_p.h" +#include + +QT_BEGIN_NAMESPACE + +QMutexPrivate::QMutexPrivate() +{ + event = CreateEvent(0, FALSE, FALSE, 0); + + if (!event) + qWarning("QMutexPrivate::QMutexPrivate: Cannot create event"); +} + +QMutexPrivate::~QMutexPrivate() +{ CloseHandle(event); } + +bool QMutexPrivate::wait(QDeadlineTimer timeout) +{ + return (WaitForSingleObjectEx(event, timeout.isForever() ? INFINITE : timeout.remainingTime(), FALSE) == WAIT_OBJECT_0); +} + +void QMutexPrivate::wakeUp() noexcept +{ SetEvent(event); } + +QT_END_NAMESPACE \ No newline at end of file diff --git a/qtbase/src/gui/rhi/qrhid3d11.cpp b/qtbase/src/gui/rhi/qrhid3d11.cpp index 8c4eac9b..70f7c5e5 100644 --- a/qtbase/src/gui/rhi/qrhid3d11.cpp +++ b/qtbase/src/gui/rhi/qrhid3d11.cpp @@ -10,6 +10,8 @@ #include #include "qrhid3dhelpers_p.h" +#include + QT_BEGIN_NAMESPACE using namespace Qt::StringLiterals; @@ -155,13 +157,22 @@ inline Int aligned(Int v, Int byteAlign) static IDXGIFactory1 *createDXGIFactory2() { + typedef HRESULT(WINAPI* CreateDXGIFactory2Func) (UINT flags, REFIID riid, void** factory); + static CreateDXGIFactory2Func myCreateDXGIFactory2 = + (CreateDXGIFactory2Func)::GetProcAddress(::GetModuleHandle(L"dxgi"), "CreateDXGIFactory2"); + IDXGIFactory1 *result = nullptr; - const HRESULT hr = CreateDXGIFactory2(0, __uuidof(IDXGIFactory2), reinterpret_cast(&result)); - if (FAILED(hr)) { - qWarning("CreateDXGIFactory2() failed to create DXGI factory: %s", - qPrintable(QSystemError::windowsComString(hr))); - result = nullptr; + + if (myCreateDXGIFactory2) + { + const HRESULT hr = myCreateDXGIFactory2(0, __uuidof(IDXGIFactory2), reinterpret_cast(&result)); + if (FAILED(hr)) { + qWarning("CreateDXGIFactory2() failed to create DXGI factory: %s", + qPrintable(QSystemError::windowsComString(hr))); + result = nullptr; + } } + return result; } @@ -4999,6 +5010,14 @@ static const DXGI_FORMAT DEFAULT_SRGB_FORMAT = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB; bool QD3D11SwapChain::createOrResize() { + if (IsWindows10OrGreater()) + { + // continue + } + else + { + return createOrResizeWin7(); + } // Can be called multiple times due to window resizes - that is not the // same as a simple destroy+create (as with other resources). Just need to // resize the buffers then. @@ -5267,4 +5286,9 @@ bool QD3D11SwapChain::createOrResize() return true; } +bool QD3D11SwapChain::createOrResizeWin7() +{ + return false; // not implemented yet ;( +} + QT_END_NAMESPACE diff --git a/qtbase/src/gui/rhi/qrhid3d11_p.h b/qtbase/src/gui/rhi/qrhid3d11_p.h index f3884f68..328323c9 100644 --- a/qtbase/src/gui/rhi/qrhid3d11_p.h +++ b/qtbase/src/gui/rhi/qrhid3d11_p.h @@ -586,7 +586,8 @@ struct QD3D11SwapChain : public QRhiSwapChain QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() override; bool createOrResize() override; - + bool createOrResizeWin7(); + void releaseBuffers(); bool newColorBuffer(const QSize &size, DXGI_FORMAT format, DXGI_SAMPLE_DESC sampleDesc, ID3D11Texture2D **tex, ID3D11RenderTargetView **rtv) const; diff --git a/qtbase/src/gui/rhi/qrhid3d12.cpp b/qtbase/src/gui/rhi/qrhid3d12.cpp index 38e4fbd2..561e6db4 100644 --- a/qtbase/src/gui/rhi/qrhid3d12.cpp +++ b/qtbase/src/gui/rhi/qrhid3d12.cpp @@ -169,12 +169,28 @@ static inline QD3D12RenderTargetData *rtData(QRhiRenderTarget *rt) bool QRhiD3D12::create(QRhi::Flags flags) { + typedef HRESULT(WINAPI* CreateDXGIFactory2Func) (UINT flags, REFIID riid, void** factory); + typedef HRESULT(WINAPI* D3D12CreateDeviceFunc) (IUnknown *, D3D_FEATURE_LEVEL, REFIID, void **); + typedef HRESULT(WINAPI* D3D12GetDebugInterfaceFunc) (REFIID, void **); + + static CreateDXGIFactory2Func myCreateDXGIFactory2 = + (CreateDXGIFactory2Func)::GetProcAddress(::GetModuleHandle(L"dxgi"), "CreateDXGIFactory2"); + + static D3D12CreateDeviceFunc myD3D12CreateDevice = + (D3D12CreateDeviceFunc)::GetProcAddress(::GetModuleHandle(L"D3d12"), "D3D12CreateDevice"); + + static D3D12GetDebugInterfaceFunc myD3D12GetDebugInterface = + (D3D12GetDebugInterfaceFunc)::GetProcAddress(::GetModuleHandle(L"D3d12"), "D3D12GetDebugInterface"); + + if (!myCreateDXGIFactory2 || !myD3D12CreateDevice || !myD3D12GetDebugInterface) + return false; + rhiFlags = flags; UINT factoryFlags = 0; if (debugLayer) factoryFlags |= DXGI_CREATE_FACTORY_DEBUG; - HRESULT hr = CreateDXGIFactory2(factoryFlags, __uuidof(IDXGIFactory2), reinterpret_cast(&dxgiFactory)); + HRESULT hr = myCreateDXGIFactory2(factoryFlags, __uuidof(IDXGIFactory2), reinterpret_cast(&dxgiFactory)); if (FAILED(hr)) { qWarning("CreateDXGIFactory2() failed to create DXGI factory: %s", qPrintable(QSystemError::windowsComString(hr))); @@ -192,7 +208,7 @@ bool QRhiD3D12::create(QRhi::Flags flags) if (debugLayer) { ID3D12Debug1 *debug = nullptr; - if (SUCCEEDED(D3D12GetDebugInterface(__uuidof(ID3D12Debug1), reinterpret_cast(&debug)))) { + if (SUCCEEDED(myD3D12GetDebugInterface(__uuidof(ID3D12Debug1), reinterpret_cast(&debug)))) { qCDebug(QRHI_LOG_INFO, "Enabling D3D12 debug layer"); debug->EnableDebugLayer(); debug->Release(); @@ -262,7 +278,7 @@ bool QRhiD3D12::create(QRhi::Flags flags) if (minimumFeatureLevel == 0) minimumFeatureLevel = MIN_FEATURE_LEVEL; - hr = D3D12CreateDevice(activeAdapter, + hr = myD3D12CreateDevice(activeAdapter, minimumFeatureLevel, __uuidof(ID3D12Device), reinterpret_cast(&dev)); @@ -2520,6 +2536,9 @@ QD3D12Descriptor QD3D12SamplerManager::getShaderVisibleDescriptor(const D3D12_SA return descriptor; } +typedef HRESULT(WINAPI* D3D12SerializeVersionedRootSignatureFunc) (const D3D12_VERSIONED_ROOT_SIGNATURE_DESC *, ID3DBlob **, ID3DBlob **); +D3D12SerializeVersionedRootSignatureFunc myD3D12SerializeVersionedRootSignature = nullptr; + bool QD3D12MipmapGenerator::create(QRhiD3D12 *rhiD) { this->rhiD = rhiD; @@ -2564,8 +2583,15 @@ bool QD3D12MipmapGenerator::create(QRhiD3D12 *rhiD) rsDesc.Desc_1_1.NumStaticSamplers = 1; rsDesc.Desc_1_1.pStaticSamplers = &samplerDesc; + if (!myD3D12SerializeVersionedRootSignature) + myD3D12SerializeVersionedRootSignature = + (D3D12SerializeVersionedRootSignatureFunc)::GetProcAddress(::GetModuleHandle(L"D3d12"), "D3D12SerializeVersionedRootSignature"); + + if (!myD3D12SerializeVersionedRootSignature) + return false; + ID3DBlob *signature = nullptr; - HRESULT hr = D3D12SerializeVersionedRootSignature(&rsDesc, &signature, nullptr); + HRESULT hr = myD3D12SerializeVersionedRootSignature(&rsDesc, &signature, nullptr); if (FAILED(hr)) { qWarning("Failed to serialize root signature: %s", qPrintable(QSystemError::windowsComString(hr))); return false; @@ -4834,8 +4860,15 @@ QD3D12ObjectHandle QD3D12ShaderResourceBindings::createRootSignature(const QD3D1 } rsDesc.Desc_1_1.Flags = D3D12_ROOT_SIGNATURE_FLAGS(rsFlags); + if (!myD3D12SerializeVersionedRootSignature) + myD3D12SerializeVersionedRootSignature = + (D3D12SerializeVersionedRootSignatureFunc)::GetProcAddress(::GetModuleHandle(L"D3d12"), "D3D12SerializeVersionedRootSignature"); + + if (!myD3D12SerializeVersionedRootSignature) + return {}; + ID3DBlob *signature = nullptr; - HRESULT hr = D3D12SerializeVersionedRootSignature(&rsDesc, &signature, nullptr); + HRESULT hr = myD3D12SerializeVersionedRootSignature(&rsDesc, &signature, nullptr); if (FAILED(hr)) { qWarning("Failed to serialize root signature: %s", qPrintable(QSystemError::windowsComString(hr))); return {}; diff --git a/qtbase/src/gui/text/windows/qwindowsfontdatabasebase.cpp b/qtbase/src/gui/text/windows/qwindowsfontdatabasebase.cpp index f9b36b48..18155cb0 100644 --- a/qtbase/src/gui/text/windows/qwindowsfontdatabasebase.cpp +++ b/qtbase/src/gui/text/windows/qwindowsfontdatabasebase.cpp @@ -685,7 +685,16 @@ QFont QWindowsFontDatabaseBase::systemDefaultFont() // Qt 6: Obtain default GUI font (typically "Segoe UI, 9pt", see QTBUG-58610) NONCLIENTMETRICS ncm = {}; ncm.cbSize = sizeof(ncm); - SystemParametersInfoForDpi(SPI_GETNONCLIENTMETRICS, ncm.cbSize, &ncm, 0, defaultVerticalDPI()); + + typedef BOOL (WINAPI *SystemParametersInfoForDpiFunc) (UINT, UINT, PVOID, UINT, UINT); + static SystemParametersInfoForDpiFunc mySystemParametersInfoForDpi = + (SystemParametersInfoForDpiFunc)::GetProcAddress(::GetModuleHandle(L"user32"), "SystemParametersInfoForDpi"); + + if (mySystemParametersInfoForDpi) + mySystemParametersInfoForDpi(SPI_GETNONCLIENTMETRICS, ncm.cbSize, &ncm, 0, defaultVerticalDPI()); + else + SystemParametersInfo(SPI_GETNONCLIENTMETRICS, ncm.cbSize , &ncm, 0); + const QFont systemFont = QWindowsFontDatabase::LOGFONT_to_QFont(ncm.lfMessageFont); qCDebug(lcQpaFonts) << __FUNCTION__ << systemFont; return systemFont; diff --git a/qtbase/src/network/kernel/qdnslookup_win.cpp b/qtbase/src/network/kernel/qdnslookup_win.cpp index 72d5ae5c..5410edab 100644 --- a/qtbase/src/network/kernel/qdnslookup_win.cpp +++ b/qtbase/src/network/kernel/qdnslookup_win.cpp @@ -65,35 +65,101 @@ QT_BEGIN_NAMESPACE void QDnsLookupRunnable::query(QDnsLookupReply *reply) { - // Perform DNS query. - alignas(DNS_ADDR_ARRAY) uchar dnsAddresses[sizeof(DNS_ADDR_ARRAY) + sizeof(DNS_ADDR)]; - DNS_QUERY_REQUEST request = {}; - request.Version = 1; - request.QueryName = reinterpret_cast(requestName.constData()); - request.QueryType = requestType; - request.QueryOptions = DNS_QUERY_STANDARD | DNS_QUERY_TREAT_AS_FQDN; + typedef BOOL (WINAPI *DnsQueryExFunc) (PDNS_QUERY_REQUEST, PDNS_QUERY_RESULT, PDNS_QUERY_CANCEL); + static DnsQueryExFunc myDnsQueryEx = + (DnsQueryExFunc)::GetProcAddress(::GetModuleHandle(L"Dnsapi"), "DnsQueryEx"); - if (!nameserver.isNull()) { - memset(dnsAddresses, 0, sizeof(dnsAddresses)); - request.pDnsServerList = new (dnsAddresses) DNS_ADDR_ARRAY; - auto addr = new (request.pDnsServerList->AddrArray) DNS_ADDR[1]; - auto sa = new (addr[0].MaxSa) sockaddr; - request.pDnsServerList->MaxCount = sizeof(dnsAddresses); - request.pDnsServerList->AddrCount = 1; - // ### setting port 53 seems to cause some systems to fail - setSockaddr(sa, nameserver, port == DnsPort ? 0 : port); - request.pDnsServerList->Family = sa->sa_family; + PDNS_RECORD ptrStart = nullptr; + + if (myDnsQueryEx) + { + // Perform DNS query. + alignas(DNS_ADDR_ARRAY) uchar dnsAddresses[sizeof(DNS_ADDR_ARRAY) + sizeof(DNS_ADDR)]; + DNS_QUERY_REQUEST request = {}; + request.Version = 1; + request.QueryName = reinterpret_cast(requestName.constData()); + request.QueryType = requestType; + request.QueryOptions = DNS_QUERY_STANDARD | DNS_QUERY_TREAT_AS_FQDN; + + if (!nameserver.isNull()) { + memset(dnsAddresses, 0, sizeof(dnsAddresses)); + request.pDnsServerList = new (dnsAddresses) DNS_ADDR_ARRAY; + auto addr = new (request.pDnsServerList->AddrArray) DNS_ADDR[1]; + auto sa = new (addr[0].MaxSa) sockaddr; + request.pDnsServerList->MaxCount = sizeof(dnsAddresses); + request.pDnsServerList->AddrCount = 1; + // ### setting port 53 seems to cause some systems to fail + setSockaddr(sa, nameserver, port == DnsPort ? 0 : port); + request.pDnsServerList->Family = sa->sa_family; + } + + DNS_QUERY_RESULT results = {}; + results.Version = 1; + const DNS_STATUS status = myDnsQueryEx(&request, &results, nullptr); + if (status >= DNS_ERROR_RCODE_FORMAT_ERROR && status <= DNS_ERROR_RCODE_LAST) + return reply->makeDnsRcodeError(status - DNS_ERROR_RCODE_FORMAT_ERROR + 1); + else if (status == ERROR_TIMEOUT) + return reply->makeTimeoutError(); + else if (status != ERROR_SUCCESS) + return reply->makeResolverSystemError(status); + + ptrStart = results.pQueryRecords; + } + else + { + // Perform DNS query. + PDNS_RECORD dns_records = 0; + QByteArray requestNameUTF8 = requestName.toUtf8(); + const QString requestNameUtf16 = QString::fromUtf8(requestNameUTF8.data(), requestNameUTF8.size()); + IP4_ARRAY srvList; + memset(&srvList, 0, sizeof(IP4_ARRAY)); + if (!nameserver.isNull()) { + if (nameserver.protocol() == QAbstractSocket::IPv4Protocol) { + // The below code is referenced from: http://support.microsoft.com/kb/831226 + srvList.AddrCount = 1; + srvList.AddrArray[0] = htonl(nameserver.toIPv4Address()); + } else if (nameserver.protocol() == QAbstractSocket::IPv6Protocol) { + // For supporting IPv6 nameserver addresses, we'll need to switch + // from DnsQuey() to DnsQueryEx() as it supports passing an IPv6 + // address in the nameserver list + qWarning("%s", "IPv6 addresses for nameservers are currently not supported"); + reply->error = QDnsLookup::ResolverError; + reply->errorString = tr("IPv6 addresses for nameservers are currently not supported"); + return; + } + } + const DNS_STATUS status = DnsQuery_W(reinterpret_cast(requestNameUtf16.utf16()), requestType, DNS_QUERY_STANDARD, &srvList, &dns_records, NULL); + switch (status) { + case ERROR_SUCCESS: + break; + case DNS_ERROR_RCODE_FORMAT_ERROR: + reply->error = QDnsLookup::InvalidRequestError; + reply->errorString = tr("Server could not process query"); + return; + case DNS_ERROR_RCODE_SERVER_FAILURE: + case DNS_ERROR_RCODE_NOT_IMPLEMENTED: + reply->error = QDnsLookup::ServerFailureError; + reply->errorString = tr("Server failure"); + return; + case DNS_ERROR_RCODE_NAME_ERROR: + reply->error = QDnsLookup::NotFoundError; + reply->errorString = tr("Non existent domain"); + return; + case DNS_ERROR_RCODE_REFUSED: + reply->error = QDnsLookup::ServerRefusedError; + reply->errorString = tr("Server refused to answer"); + return; + default: + reply->error = QDnsLookup::InvalidReplyError; + reply->errorString = QSystemError(status, QSystemError::NativeError).toString(); + return; + } + + ptrStart = dns_records; } - DNS_QUERY_RESULT results = {}; - results.Version = 1; - const DNS_STATUS status = DnsQueryEx(&request, &results, nullptr); - if (status >= DNS_ERROR_RCODE_FORMAT_ERROR && status <= DNS_ERROR_RCODE_LAST) - return reply->makeDnsRcodeError(status - DNS_ERROR_RCODE_FORMAT_ERROR + 1); - else if (status == ERROR_TIMEOUT) - return reply->makeTimeoutError(); - else if (status != ERROR_SUCCESS) - return reply->makeResolverSystemError(status); + if (!ptrStart) + return; QStringView lastEncodedName; QString cachedDecodedName; @@ -105,9 +171,9 @@ void QDnsLookupRunnable::query(QDnsLookupReply *reply) auto extractMaybeCachedHost = [&](QStringView name) -> const QString & { return lastEncodedName == name ? cachedDecodedName : extractAndCacheHost(name); }; - + // Extract results. - for (PDNS_RECORD ptr = results.pQueryRecords; ptr != NULL; ptr = ptr->pNext) { + for (PDNS_RECORD ptr = ptrStart; ptr != NULL; ptr = ptr->pNext) { // warning: always assign name to the record before calling extractXxxHost() again const QString &name = extractMaybeCachedHost(ptr->pName); if (ptr->wType == QDnsLookup::A) { @@ -170,7 +236,7 @@ void QDnsLookupRunnable::query(QDnsLookupReply *reply) } } - DnsRecordListFree(results.pQueryRecords, DnsFreeRecordList); + DnsRecordListFree(ptrStart, DnsFreeRecordList); } QT_END_NAMESPACE diff --git a/qtbase/src/plugins/platforms/windows/qwin10helpers.cpp b/qtbase/src/plugins/platforms/windows/qwin10helpers.cpp index 026e81cb..cbe4fa89 100644 --- a/qtbase/src/plugins/platforms/windows/qwin10helpers.cpp +++ b/qtbase/src/plugins/platforms/windows/qwin10helpers.cpp @@ -58,43 +58,73 @@ public: } // namespace ABI #endif // HAS_UI_VIEW_SETTINGS +// based on SDL approach +// see SDL_windows_gaming_input.c, SDL_windows.c + +void * WIN_LoadComBaseFunction(const char *name) +{ + static bool s_bLoaded = false; + static HMODULE s_hComBase = NULL; + + if (!s_bLoaded) { + s_hComBase = ::LoadLibraryEx(L"combase.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32); + s_bLoaded = true; + } + if (s_hComBase) { + return ::GetProcAddress(s_hComBase, name); + } else { + return NULL; + } +} + QT_BEGIN_NAMESPACE // Return tablet mode, note: Does not work for GetDesktopWindow(). bool qt_windowsIsTabletMode(HWND hwnd) { - bool result = false; + typedef HRESULT (WINAPI *WindowsCreateStringReference_t)(PCWSTR sourceString, UINT32 length, HSTRING_HEADER *hstringHeader, HSTRING* string); + typedef HRESULT (WINAPI *RoGetActivationFactory_t)(HSTRING activatableClassId, REFIID iid, void** factory); - 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; + WindowsCreateStringReference_t WindowsCreateStringReferenceFunc = (WindowsCreateStringReference_t)WIN_LoadComBaseFunction("WindowsCreateStringReference"); + RoGetActivationFactory_t RoGetActivationFactoryFunc = (RoGetActivationFactory_t)WIN_LoadComBaseFunction("RoGetActivationFactory"); - IUIViewSettingsInterop *uiViewSettingsInterop = nullptr; - // __uuidof(IUIViewSettingsInterop); - const GUID uiViewSettingsInteropRefId = {0x3694dbf9, 0x8f68, 0x44be,{0x8f, 0xf5, 0x19, 0x5c, 0x98, 0xed, 0xe8, 0xa6}}; + if (WindowsCreateStringReferenceFunc && RoGetActivationFactoryFunc) + { + bool result = false; - HRESULT hr = RoGetActivationFactory(uiViewSettingsIdHs, uiViewSettingsInteropRefId, - reinterpret_cast(&uiViewSettingsInterop)); - if (FAILED(hr)) - return 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(WindowsCreateStringReferenceFunc(uiViewSettingsId, uiViewSettingsIdLen, &uiViewSettingsIdRefHeader, &uiViewSettingsIdHs))) + 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(&viewSettings)); - if (SUCCEEDED(hr)) { - ABI::Windows::UI::ViewManagement::UserInteractionMode currentMode; - hr = viewSettings->get_UserInteractionMode(¤tMode); - if (SUCCEEDED(hr)) - result = currentMode == 1; // Touch, 1 - viewSettings->Release(); + IUIViewSettingsInterop *uiViewSettingsInterop = nullptr; + // __uuidof(IUIViewSettingsInterop); + const GUID uiViewSettingsInteropRefId = {0x3694dbf9, 0x8f68, 0x44be,{0x8f, 0xf5, 0x19, 0x5c, 0x98, 0xed, 0xe8, 0xa6}}; + + HRESULT hr = RoGetActivationFactoryFunc(uiViewSettingsIdHs, uiViewSettingsInteropRefId, + reinterpret_cast(&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(&viewSettings)); + if (SUCCEEDED(hr)) { + ABI::Windows::UI::ViewManagement::UserInteractionMode currentMode; + hr = viewSettings->get_UserInteractionMode(¤tMode); + if (SUCCEEDED(hr)) + result = currentMode == 1; // Touch, 1 + viewSettings->Release(); + } + uiViewSettingsInterop->Release(); + return result; } - uiViewSettingsInterop->Release(); - return result; + + return false; } -QT_END_NAMESPACE +QT_END_NAMESPACE \ No newline at end of file diff --git a/qtbase/src/plugins/platforms/windows/qwindowscontext.cpp b/qtbase/src/plugins/platforms/windows/qwindowscontext.cpp index 72a3ca15..9447fcfc 100644 --- a/qtbase/src/plugins/platforms/windows/qwindowscontext.cpp +++ b/qtbase/src/plugins/platforms/windows/qwindowscontext.cpp @@ -44,6 +44,7 @@ #include #include #include +#include #include #include #include @@ -118,6 +119,77 @@ static inline bool sessionManagerInteractionBlocked() static inline bool sessionManagerInteractionBlocked() { return false; } #endif +/*! + \class QWindowsUser32DLL + \brief Struct that contains dynamically resolved symbols of User32.dll. + The stub libraries shipped with the MinGW compiler miss some of the + functions. They need to be retrieved dynamically. + In addition, touch-related functions are available only from Windows onwards. + These need to resolved dynamically for Q_CC_MSVC as well. + \sa QWindowsShell32DLL + \internal +*/ + +void QWindowsUser32DLL::init() +{ + QSystemLibrary library(QStringLiteral("user32")); + setProcessDPIAware = (SetProcessDPIAware)library.resolve("SetProcessDPIAware"); + setProcessDpiAwarenessContext = (SetProcessDpiAwarenessContext)library.resolve("SetProcessDpiAwarenessContext"); + getThreadDpiAwarenessContext = (GetThreadDpiAwarenessContext)library.resolve("GetThreadDpiAwarenessContext"); + isValidDpiAwarenessContext = (IsValidDpiAwarenessContext)library.resolve("IsValidDpiAwarenessContext"); + areDpiAwarenessContextsEqual = (AreDpiAwarenessContextsEqual)library.resolve("AreDpiAwarenessContextsEqual"); + + addClipboardFormatListener = (AddClipboardFormatListener)library.resolve("AddClipboardFormatListener"); + removeClipboardFormatListener = (RemoveClipboardFormatListener)library.resolve("RemoveClipboardFormatListener"); + + getDisplayAutoRotationPreferences = (GetDisplayAutoRotationPreferences)library.resolve("GetDisplayAutoRotationPreferences"); + setDisplayAutoRotationPreferences = (SetDisplayAutoRotationPreferences)library.resolve("SetDisplayAutoRotationPreferences"); + + if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows8) { + enableMouseInPointer = (EnableMouseInPointer)library.resolve("EnableMouseInPointer"); + getPointerType = (GetPointerType)library.resolve("GetPointerType"); + getPointerInfo = (GetPointerInfo)library.resolve("GetPointerInfo"); + getPointerDeviceRects = (GetPointerDeviceRects)library.resolve("GetPointerDeviceRects"); + getPointerTouchInfo = (GetPointerTouchInfo)library.resolve("GetPointerTouchInfo"); + getPointerFrameTouchInfo = (GetPointerFrameTouchInfo)library.resolve("GetPointerFrameTouchInfo"); + getPointerFrameTouchInfoHistory = (GetPointerFrameTouchInfoHistory)library.resolve("GetPointerFrameTouchInfoHistory"); + getPointerPenInfo = (GetPointerPenInfo)library.resolve("GetPointerPenInfo"); + getPointerPenInfoHistory = (GetPointerPenInfoHistory)library.resolve("GetPointerPenInfoHistory"); + skipPointerFrameMessages = (SkipPointerFrameMessages)library.resolve("SkipPointerFrameMessages"); + } + + if (QOperatingSystemVersion::current() + >= QOperatingSystemVersion(QOperatingSystemVersion::Windows, 10, 0, 14393)) { + adjustWindowRectExForDpi = (AdjustWindowRectExForDpi)library.resolve("AdjustWindowRectExForDpi"); + enableNonClientDpiScaling = (EnableNonClientDpiScaling)library.resolve("EnableNonClientDpiScaling"); + getWindowDpiAwarenessContext = (GetWindowDpiAwarenessContext)library.resolve("GetWindowDpiAwarenessContext"); + getAwarenessFromDpiAwarenessContext = (GetAwarenessFromDpiAwarenessContext)library.resolve("GetAwarenessFromDpiAwarenessContext"); + systemParametersInfoForDpi = (SystemParametersInfoForDpi)library.resolve("SystemParametersInfoForDpi"); + getDpiForWindow = (GetDpiForWindow)library.resolve("GetDpiForWindow"); + getSystemMetricsForDpi = (GetSystemMetricsForDpi)library.resolve("GetSystemMetricsForDpi"); + } +} + +bool QWindowsUser32DLL::supportsPointerApi() +{ + return enableMouseInPointer && getPointerType && getPointerInfo && getPointerDeviceRects + && getPointerTouchInfo && getPointerFrameTouchInfo && getPointerFrameTouchInfoHistory + && getPointerPenInfo && getPointerPenInfoHistory && skipPointerFrameMessages; +} + +void QWindowsShcoreDLL::init() +{ + if (QOperatingSystemVersion::current() < QOperatingSystemVersion::Windows8_1) + return; + QSystemLibrary library(QStringLiteral("SHCore")); + getProcessDpiAwareness = (GetProcessDpiAwareness)library.resolve("GetProcessDpiAwareness"); + setProcessDpiAwareness = (SetProcessDpiAwareness)library.resolve("SetProcessDpiAwareness"); + getDpiForMonitor = (GetDpiForMonitor)library.resolve("GetDpiForMonitor"); +} + +QWindowsUser32DLL QWindowsContext::user32dll; +QWindowsShcoreDLL QWindowsContext::shcoredll; + QWindowsContext *QWindowsContext::m_instance = nullptr; /*! @@ -161,6 +233,9 @@ bool QWindowsContextPrivate::m_v2DpiAware = false; QWindowsContextPrivate::QWindowsContextPrivate() : m_oleInitializeResult(OleInitialize(nullptr)) { + QWindowsContext::user32dll.init(); + QWindowsContext::shcoredll.init(); + if (m_pointerHandler.touchDevice() || m_mouseHandler.touchDevice()) m_systemInfo |= QWindowsContext::SI_SupportsTouch; m_displayContext = GetDC(nullptr); @@ -279,6 +354,12 @@ bool QWindowsContext::initPointer(unsigned integrationOptions) if (integrationOptions & QWindowsIntegration::DontUseWMPointer) return false; + if (QOperatingSystemVersion::current() < QOperatingSystemVersion::Windows8) + return false; + + if (!QWindowsContext::user32dll.supportsPointerApi()) + return false; + d->m_systemInfo |= QWindowsContext::SI_SupportsPointer; return true; } @@ -349,41 +430,58 @@ void QWindowsContext::setDetectAltGrModifier(bool a) [[nodiscard]] static inline QtWindows::DpiAwareness dpiAwarenessContextToQtDpiAwareness(DPI_AWARENESS_CONTEXT context) { - // IsValidDpiAwarenessContext() will handle the NULL pointer case. - if (!IsValidDpiAwarenessContext(context)) + if (QWindowsContext::user32dll.isValidDpiAwarenessContext && QWindowsContext::user32dll.areDpiAwarenessContextsEqual) + { + // IsValidDpiAwarenessContext() will handle the NULL pointer case. + if (!QWindowsContext::user32dll.isValidDpiAwarenessContext(context)) + return QtWindows::DpiAwareness::Invalid; + if (QWindowsContext::user32dll.areDpiAwarenessContextsEqual(context, DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED)) + return QtWindows::DpiAwareness::Unaware_GdiScaled; + if (QWindowsContext::user32dll.areDpiAwarenessContextsEqual(context, DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2)) + return QtWindows::DpiAwareness::PerMonitorVersion2; + if (QWindowsContext::user32dll.areDpiAwarenessContextsEqual(context, DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE)) + return QtWindows::DpiAwareness::PerMonitor; + if (QWindowsContext::user32dll.areDpiAwarenessContextsEqual(context, DPI_AWARENESS_CONTEXT_SYSTEM_AWARE)) + return QtWindows::DpiAwareness::System; + if (QWindowsContext::user32dll.areDpiAwarenessContextsEqual(context, DPI_AWARENESS_CONTEXT_UNAWARE)) + return QtWindows::DpiAwareness::Unaware; + return QtWindows::DpiAwareness::Invalid; - if (AreDpiAwarenessContextsEqual(context, DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED)) - return QtWindows::DpiAwareness::Unaware_GdiScaled; - if (AreDpiAwarenessContextsEqual(context, DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2)) - return QtWindows::DpiAwareness::PerMonitorVersion2; - if (AreDpiAwarenessContextsEqual(context, DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE)) - return QtWindows::DpiAwareness::PerMonitor; - if (AreDpiAwarenessContextsEqual(context, DPI_AWARENESS_CONTEXT_SYSTEM_AWARE)) - return QtWindows::DpiAwareness::System; - if (AreDpiAwarenessContextsEqual(context, DPI_AWARENESS_CONTEXT_UNAWARE)) - return QtWindows::DpiAwareness::Unaware; - return QtWindows::DpiAwareness::Invalid; + } + + return QtWindows::DpiAwareness::Unaware; // Windows 7 } QtWindows::DpiAwareness QWindowsContext::windowDpiAwareness(HWND hwnd) { if (!hwnd) return QtWindows::DpiAwareness::Invalid; - const auto context = GetWindowDpiAwarenessContext(hwnd); - return dpiAwarenessContextToQtDpiAwareness(context); + + if (QWindowsContext::user32dll.getWindowDpiAwarenessContext) + { + const auto context = QWindowsContext::user32dll.getWindowDpiAwarenessContext(hwnd); + return dpiAwarenessContextToQtDpiAwareness(context); + } + + return dpiAwarenessContextToQtDpiAwareness(DPI_AWARENESS_CONTEXT_UNAWARE); } QtWindows::DpiAwareness QWindowsContext::processDpiAwareness() { - // Although we have GetDpiAwarenessContextForProcess(), however, - // it's only available on Win10 1903+, which is a little higher - // than Qt's minimum supported version (1809), so we can't use it. - // Luckily, MS docs said GetThreadDpiAwarenessContext() will also - // return the default DPI_AWARENESS_CONTEXT for the process if - // SetThreadDpiAwarenessContext() was never called. So we can use - // it as an equivalent. - const auto context = GetThreadDpiAwarenessContext(); - return dpiAwarenessContextToQtDpiAwareness(context); + if (QWindowsContext::user32dll.getThreadDpiAwarenessContext) + { + // Although we have GetDpiAwarenessContextForProcess(), however, + // it's only available on Win10 1903+, which is a little higher + // than Qt's minimum supported version (1809), so we can't use it. + // Luckily, MS docs said GetThreadDpiAwarenessContext() will also + // return the default DPI_AWARENESS_CONTEXT for the process if + // SetThreadDpiAwarenessContext() was never called. So we can use + // it as an equivalent. + const auto context = QWindowsContext::user32dll.getThreadDpiAwarenessContext(); + return dpiAwarenessContextToQtDpiAwareness(context); + } + + return dpiAwarenessContextToQtDpiAwareness(DPI_AWARENESS_CONTEXT_UNAWARE); } [[nodiscard]] static inline DPI_AWARENESS_CONTEXT @@ -442,23 +540,29 @@ bool QWindowsContext::setProcessDpiAwareness(QtWindows::DpiAwareness dpiAwarenes if (processDpiAwareness() == dpiAwareness) return true; const auto context = qtDpiAwarenessToDpiAwarenessContext(dpiAwareness); - if (!IsValidDpiAwarenessContext(context)) { - qCWarning(lcQpaWindow) << dpiAwareness << "is not supported by current system."; - return false; + + if (QWindowsContext::user32dll.isValidDpiAwarenessContext && QWindowsContext::user32dll.setProcessDpiAwarenessContext) + { + if (!QWindowsContext::user32dll.isValidDpiAwarenessContext(context)) { + qCWarning(lcQpaWindow) << dpiAwareness << "is not supported by current system."; + return false; + } + if (!QWindowsContext::user32dll.setProcessDpiAwarenessContext(context)) { + qCWarning(lcQpaWindow).noquote().nospace() + << "SetProcessDpiAwarenessContext() failed: " + << QSystemError::windowsString() + << "\nQt's default DPI awareness context is " + << "DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2. If you know what you " + << "are doing, you can overwrite this default using qt.conf " + << "(https://doc.qt.io/qt-6/highdpi.html#configuring-windows)."; + return false; + } + QWindowsContextPrivate::m_v2DpiAware + = processDpiAwareness() == QtWindows::DpiAwareness::PerMonitorVersion2; + return true; } - if (!SetProcessDpiAwarenessContext(context)) { - qCWarning(lcQpaWindow).noquote().nospace() - << "SetProcessDpiAwarenessContext() failed: " - << QSystemError::windowsString() - << "\nQt's default DPI awareness context is " - << "DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2. If you know what you " - << "are doing, you can overwrite this default using qt.conf " - << "(https://doc.qt.io/qt-6/highdpi.html#configuring-windows)."; - return false; - } - QWindowsContextPrivate::m_v2DpiAware - = processDpiAwareness() == QtWindows::DpiAwareness::PerMonitorVersion2; - return true; + + return false; // Windows 7 } bool QWindowsContext::isDarkMode() @@ -886,8 +990,8 @@ void QWindowsContext::forceNcCalcSize(HWND hwnd) bool QWindowsContext::systemParametersInfo(unsigned action, unsigned param, void *out, unsigned dpi) { - const BOOL result = dpi != 0 - ? SystemParametersInfoForDpi(action, param, out, 0, dpi) + const BOOL result = (QWindowsContext::user32dll.systemParametersInfoForDpi != nullptr && dpi != 0) + ? QWindowsContext::user32dll.systemParametersInfoForDpi(action, param, out, 0, dpi) : SystemParametersInfo(action, param, out, 0); return result == TRUE; } @@ -974,8 +1078,8 @@ static inline bool isInputMessage(UINT m) static bool enableNonClientDpiScaling(HWND hwnd) { bool result = false; - if (QWindowsContext::windowDpiAwareness(hwnd) == QtWindows::DpiAwareness::PerMonitor) { - result = EnableNonClientDpiScaling(hwnd) != FALSE; + if (QWindowsContext::user32dll.enableNonClientDpiScaling && QWindowsContext::windowDpiAwareness(hwnd) == QtWindows::DpiAwareness::PerMonitor) { + result = QWindowsContext::user32dll.enableNonClientDpiScaling(hwnd) != FALSE; if (!result) { const DWORD errorCode = GetLastError(); qErrnoWarning(int(errorCode), "EnableNonClientDpiScaling() failed for HWND %p (%lu)", diff --git a/qtbase/src/plugins/platforms/windows/qwindowscontext.h b/qtbase/src/plugins/platforms/windows/qwindowscontext.h index 1a3b47be..d35c58de 100644 --- a/qtbase/src/plugins/platforms/windows/qwindowscontext.h +++ b/qtbase/src/plugins/platforms/windows/qwindowscontext.h @@ -14,6 +14,7 @@ #define STRICT_TYPED_ITEMIDS #include #include +#include QT_BEGIN_NAMESPACE @@ -44,6 +45,94 @@ class QPoint; class QKeyEvent; class QPointingDevice; +struct QWindowsUser32DLL +{ + inline void init(); + inline bool supportsPointerApi(); + + typedef BOOL (WINAPI *EnableMouseInPointer)(BOOL); + typedef BOOL (WINAPI *GetPointerType)(UINT32, PVOID); + typedef BOOL (WINAPI *GetPointerInfo)(UINT32, PVOID); + typedef BOOL (WINAPI *GetPointerDeviceRects)(HANDLE, RECT *, RECT *); + typedef BOOL (WINAPI *GetPointerTouchInfo)(UINT32, PVOID); + typedef BOOL (WINAPI *GetPointerFrameTouchInfo)(UINT32, UINT32 *, PVOID); + typedef BOOL (WINAPI *GetPointerFrameTouchInfoHistory)(UINT32, UINT32 *, UINT32 *, PVOID); + typedef BOOL (WINAPI *GetPointerPenInfo)(UINT32, PVOID); + typedef BOOL (WINAPI *GetPointerPenInfoHistory)(UINT32, UINT32 *, PVOID); + typedef BOOL (WINAPI *SkipPointerFrameMessages)(UINT32); + typedef BOOL (WINAPI *SetProcessDPIAware)(); + typedef BOOL (WINAPI *SetProcessDpiAwarenessContext)(HANDLE); + typedef BOOL (WINAPI *AddClipboardFormatListener)(HWND); + typedef BOOL (WINAPI *RemoveClipboardFormatListener)(HWND); + typedef BOOL (WINAPI *GetDisplayAutoRotationPreferences)(DWORD *); + typedef BOOL (WINAPI *SetDisplayAutoRotationPreferences)(DWORD); + typedef BOOL (WINAPI *AdjustWindowRectExForDpi)(LPRECT,DWORD,BOOL,DWORD,UINT); + typedef BOOL (WINAPI *EnableNonClientDpiScaling)(HWND); + typedef DPI_AWARENESS_CONTEXT (WINAPI *GetWindowDpiAwarenessContext)(HWND); + typedef DPI_AWARENESS (WINAPI *GetAwarenessFromDpiAwarenessContext)(int); + typedef BOOL (WINAPI *SystemParametersInfoForDpi)(UINT, UINT, PVOID, UINT, UINT); + typedef int (WINAPI *GetDpiForWindow)(HWND); + typedef BOOL (WINAPI *GetSystemMetricsForDpi)(INT, UINT); + typedef BOOL (WINAPI *AreDpiAwarenessContextsEqual)(DPI_AWARENESS_CONTEXT, DPI_AWARENESS_CONTEXT); + typedef DPI_AWARENESS_CONTEXT (WINAPI *GetThreadDpiAwarenessContext)(); + typedef BOOL (WINAPI *IsValidDpiAwarenessContext)(DPI_AWARENESS_CONTEXT); + + // Windows pointer functions (Windows 8 or later). + EnableMouseInPointer enableMouseInPointer = nullptr; + GetPointerType getPointerType = nullptr; + GetPointerInfo getPointerInfo = nullptr; + GetPointerDeviceRects getPointerDeviceRects = nullptr; + GetPointerTouchInfo getPointerTouchInfo = nullptr; + GetPointerFrameTouchInfo getPointerFrameTouchInfo = nullptr; + GetPointerFrameTouchInfoHistory getPointerFrameTouchInfoHistory = nullptr; + GetPointerPenInfo getPointerPenInfo = nullptr; + GetPointerPenInfoHistory getPointerPenInfoHistory = nullptr; + SkipPointerFrameMessages skipPointerFrameMessages = nullptr; + + // Windows Vista onwards + SetProcessDPIAware setProcessDPIAware = nullptr; + + // Windows 10 version 1607 onwards + GetDpiForWindow getDpiForWindow = nullptr; + GetThreadDpiAwarenessContext getThreadDpiAwarenessContext = nullptr; + IsValidDpiAwarenessContext isValidDpiAwarenessContext = nullptr; + + // Windows 10 version 1703 onwards + SetProcessDpiAwarenessContext setProcessDpiAwarenessContext = nullptr; + AreDpiAwarenessContextsEqual areDpiAwarenessContextsEqual = nullptr; + + // Clipboard listeners are present on Windows Vista onwards + // but missing in MinGW 4.9 stub libs. Can be removed in MinGW 5. + AddClipboardFormatListener addClipboardFormatListener = nullptr; + RemoveClipboardFormatListener removeClipboardFormatListener = nullptr; + + // Rotation API + GetDisplayAutoRotationPreferences getDisplayAutoRotationPreferences = nullptr; + SetDisplayAutoRotationPreferences setDisplayAutoRotationPreferences = nullptr; + + AdjustWindowRectExForDpi adjustWindowRectExForDpi = nullptr; + EnableNonClientDpiScaling enableNonClientDpiScaling = nullptr; + GetWindowDpiAwarenessContext getWindowDpiAwarenessContext = nullptr; + GetAwarenessFromDpiAwarenessContext getAwarenessFromDpiAwarenessContext = nullptr; + SystemParametersInfoForDpi systemParametersInfoForDpi = nullptr; + GetSystemMetricsForDpi getSystemMetricsForDpi = nullptr; +}; + +// Shell scaling library (Windows 8.1 onwards) +struct QWindowsShcoreDLL +{ + void init(); + inline bool isValid() const { return getProcessDpiAwareness && setProcessDpiAwareness && getDpiForMonitor; } + + typedef HRESULT (WINAPI *GetProcessDpiAwareness)(HANDLE,PROCESS_DPI_AWARENESS *); + typedef HRESULT (WINAPI *SetProcessDpiAwareness)(PROCESS_DPI_AWARENESS); + typedef HRESULT (WINAPI *GetDpiForMonitor)(HMONITOR,int,UINT *,UINT *); + + GetProcessDpiAwareness getProcessDpiAwareness = nullptr; + SetProcessDpiAwareness setProcessDpiAwareness = nullptr; + GetDpiForMonitor getDpiForMonitor = nullptr; +}; + class QWindowsContext { Q_DISABLE_COPY_MOVE(QWindowsContext) @@ -138,6 +227,9 @@ public: QWindowsScreenManager &screenManager(); QWindowsTabletSupport *tabletSupport() const; + static QWindowsUser32DLL user32dll; + static QWindowsShcoreDLL shcoredll; + bool asyncExpose() const; void setAsyncExpose(bool value); diff --git a/qtbase/src/plugins/platforms/windows/qwindowsdrag.cpp b/qtbase/src/plugins/platforms/windows/qwindowsdrag.cpp index b797217c..ea2439e9 100644 --- a/qtbase/src/plugins/platforms/windows/qwindowsdrag.cpp +++ b/qtbase/src/plugins/platforms/windows/qwindowsdrag.cpp @@ -670,7 +670,7 @@ static HRESULT startDoDragDrop(LPDATAOBJECT pDataObj, LPDROPSOURCE pDropSource, const quint32 pointerId = GET_POINTERID_WPARAM(msg.wParam); POINTER_INFO pointerInfo{}; - if (!GetPointerInfo(pointerId, &pointerInfo)) + if (!QWindowsContext::user32dll.getPointerInfo || !QWindowsContext::user32dll.getPointerInfo(pointerId, &pointerInfo)) return E_FAIL; if (pointerInfo.pointerFlags & POINTER_FLAG_PRIMARY) { diff --git a/qtbase/src/plugins/platforms/windows/qwindowskeymapper.cpp b/qtbase/src/plugins/platforms/windows/qwindowskeymapper.cpp index 3089e745..4b219c34 100644 --- a/qtbase/src/plugins/platforms/windows/qwindowskeymapper.cpp +++ b/qtbase/src/plugins/platforms/windows/qwindowskeymapper.cpp @@ -751,15 +751,28 @@ static inline QString messageKeyText(const MSG &msg) [[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; + if (QWindowsContext::user32dll.getDpiForWindow && QWindowsContext::user32dll.getSystemMetricsForDpi) + { + const UINT dpi = QWindowsContext::user32dll.getDpiForWindow(hwnd); + const int captionHeight = QWindowsContext::user32dll.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 = QWindowsContext::user32dll.getSystemMetricsForDpi(SM_CYSIZEFRAME, dpi) + + QWindowsContext::user32dll.getSystemMetricsForDpi(SM_CXPADDEDBORDER, dpi); + return captionHeight + frameHeight; + } + else + { + const int captionHeight = GetSystemMetrics(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 = GetSystemMetrics(SM_CYSIZEFRAME) + GetSystemMetrics(SM_CXPADDEDBORDER); + return captionHeight + frameHeight; + } } [[nodiscard]] static inline bool isSystemMenuOffsetNeeded(const Qt::WindowFlags flags) diff --git a/qtbase/src/plugins/platforms/windows/qwindowspointerhandler.cpp b/qtbase/src/plugins/platforms/windows/qwindowspointerhandler.cpp index 77ed0f84..26a2b027 100644 --- a/qtbase/src/plugins/platforms/windows/qwindowspointerhandler.cpp +++ b/qtbase/src/plugins/platforms/windows/qwindowspointerhandler.cpp @@ -48,7 +48,7 @@ bool QWindowsPointerHandler::translatePointerEvent(QWindow *window, HWND hwnd, Q *result = 0; const quint32 pointerId = GET_POINTERID_WPARAM(msg.wParam); - if (!GetPointerType(pointerId, &m_pointerType)) { + if (!QWindowsContext::user32dll.getPointerType(pointerId, &m_pointerType)) { qWarning() << "GetPointerType() failed:" << qt_error_string(); return false; } @@ -62,12 +62,12 @@ bool QWindowsPointerHandler::translatePointerEvent(QWindow *window, HWND hwnd, Q } case QT_PT_TOUCH: { quint32 pointerCount = 0; - if (!GetPointerFrameTouchInfo(pointerId, &pointerCount, nullptr)) { + if (!QWindowsContext::user32dll.getPointerFrameTouchInfo(pointerId, &pointerCount, nullptr)) { qWarning() << "GetPointerFrameTouchInfo() failed:" << qt_error_string(); return false; } QVarLengthArray touchInfo(pointerCount); - if (!GetPointerFrameTouchInfo(pointerId, &pointerCount, touchInfo.data())) { + if (!QWindowsContext::user32dll.getPointerFrameTouchInfo(pointerId, &pointerCount, touchInfo.data())) { qWarning() << "GetPointerFrameTouchInfo() failed:" << qt_error_string(); return false; } @@ -80,10 +80,10 @@ bool QWindowsPointerHandler::translatePointerEvent(QWindow *window, HWND hwnd, Q // dispatch any skipped frames if event compression is disabled by the app if (historyCount > 1 && !QCoreApplication::testAttribute(Qt::AA_CompressHighFrequencyEvents)) { touchInfo.resize(pointerCount * historyCount); - if (!GetPointerFrameTouchInfoHistory(pointerId, - &historyCount, - &pointerCount, - touchInfo.data())) { + if (!QWindowsContext::user32dll.getPointerFrameTouchInfoHistory(pointerId, + &historyCount, + &pointerCount, + touchInfo.data())) { qWarning() << "GetPointerFrameTouchInfoHistory() failed:" << qt_error_string(); return false; } @@ -101,7 +101,7 @@ bool QWindowsPointerHandler::translatePointerEvent(QWindow *window, HWND hwnd, Q } case QT_PT_PEN: { POINTER_PEN_INFO penInfo; - if (!GetPointerPenInfo(pointerId, &penInfo)) { + if (!QWindowsContext::user32dll.getPointerPenInfo(pointerId, &penInfo)) { qWarning() << "GetPointerPenInfo() failed:" << qt_error_string(); return false; } @@ -113,7 +113,7 @@ bool QWindowsPointerHandler::translatePointerEvent(QWindow *window, HWND hwnd, Q || !QCoreApplication::testAttribute(Qt::AA_CompressTabletEvents))) { QVarLengthArray penInfoHistory(historyCount); - if (!GetPointerPenInfoHistory(pointerId, &historyCount, penInfoHistory.data())) { + if (!QWindowsContext::user32dll.getPointerPenInfoHistory(pointerId, &historyCount, penInfoHistory.data())) { qWarning() << "GetPointerPenInfoHistory() failed:" << qt_error_string(); return false; } @@ -519,7 +519,7 @@ bool QWindowsPointerHandler::translateTouchEvent(QWindow *window, HWND hwnd, inputIds.insert(touchPoint.id); // Avoid getting repeated messages for this frame if there are multiple pointerIds - SkipPointerFrameMessages(touchInfo[i].pointerInfo.pointerId); + QWindowsContext::user32dll.skipPointerFrameMessages(touchInfo[i].pointerInfo.pointerId); } // Some devices send touches for each finger in a different message/frame, instead of consolidating @@ -565,7 +565,7 @@ bool QWindowsPointerHandler::translatePenEvent(QWindow *window, HWND hwnd, QtWin auto *penInfo = static_cast(vPenInfo); RECT pRect, dRect; - if (!GetPointerDeviceRects(penInfo->pointerInfo.sourceDevice, &pRect, &dRect)) + if (!QWindowsContext::user32dll.getPointerDeviceRects(penInfo->pointerInfo.sourceDevice, &pRect, &dRect)) return false; const auto systemId = (qint64)penInfo->pointerInfo.sourceDevice; diff --git a/qtbase/src/plugins/platforms/windows/qwindowsscreen.cpp b/qtbase/src/plugins/platforms/windows/qwindowsscreen.cpp index 15c5aac8..b78b6d54 100644 --- a/qtbase/src/plugins/platforms/windows/qwindowsscreen.cpp +++ b/qtbase/src/plugins/platforms/windows/qwindowsscreen.cpp @@ -42,10 +42,12 @@ static inline QDpi deviceDPI(HDC hdc) static inline QDpi monitorDPI(HMONITOR hMonitor) { - UINT dpiX; - UINT dpiY; - if (SUCCEEDED(GetDpiForMonitor(hMonitor, MDT_EFFECTIVE_DPI, &dpiX, &dpiY))) - return QDpi(dpiX, dpiY); + if (QWindowsContext::shcoredll.isValid()) { + UINT dpiX; + UINT dpiY; + if (SUCCEEDED(QWindowsContext::shcoredll.getDpiForMonitor(hMonitor, MDT_EFFECTIVE_DPI, &dpiX, &dpiY))) + return QDpi(dpiX, dpiY); + } return {0, 0}; } @@ -570,47 +572,51 @@ QRect QWindowsScreen::virtualGeometry(const QPlatformScreen *screen) // cf QScre bool QWindowsScreen::setOrientationPreference(Qt::ScreenOrientation o) { bool result = false; - ORIENTATION_PREFERENCE orientationPreference = ORIENTATION_PREFERENCE_NONE; - switch (o) { - case Qt::PrimaryOrientation: - break; - case Qt::PortraitOrientation: - orientationPreference = ORIENTATION_PREFERENCE_PORTRAIT; - break; - case Qt::LandscapeOrientation: - orientationPreference = ORIENTATION_PREFERENCE_LANDSCAPE; - break; - case Qt::InvertedPortraitOrientation: - orientationPreference = ORIENTATION_PREFERENCE_PORTRAIT_FLIPPED; - break; - case Qt::InvertedLandscapeOrientation: - orientationPreference = ORIENTATION_PREFERENCE_LANDSCAPE_FLIPPED; - break; + if (QWindowsContext::user32dll.setDisplayAutoRotationPreferences) { + ORIENTATION_PREFERENCE orientationPreference = ORIENTATION_PREFERENCE_NONE; + switch (o) { + case Qt::PrimaryOrientation: + break; + case Qt::PortraitOrientation: + orientationPreference = ORIENTATION_PREFERENCE_PORTRAIT; + break; + case Qt::LandscapeOrientation: + orientationPreference = ORIENTATION_PREFERENCE_LANDSCAPE; + break; + case Qt::InvertedPortraitOrientation: + orientationPreference = ORIENTATION_PREFERENCE_PORTRAIT_FLIPPED; + break; + case Qt::InvertedLandscapeOrientation: + orientationPreference = ORIENTATION_PREFERENCE_LANDSCAPE_FLIPPED; + break; + } + result = QWindowsContext::user32dll.setDisplayAutoRotationPreferences(orientationPreference); } - result = SetDisplayAutoRotationPreferences(orientationPreference); return result; } Qt::ScreenOrientation QWindowsScreen::orientationPreference() { Qt::ScreenOrientation result = Qt::PrimaryOrientation; - ORIENTATION_PREFERENCE orientationPreference = ORIENTATION_PREFERENCE_NONE; - if (GetDisplayAutoRotationPreferences(&orientationPreference)) { - switch (orientationPreference) { - case ORIENTATION_PREFERENCE_NONE: - break; - case ORIENTATION_PREFERENCE_LANDSCAPE: - result = Qt::LandscapeOrientation; - break; - case ORIENTATION_PREFERENCE_PORTRAIT: - result = Qt::PortraitOrientation; - break; - case ORIENTATION_PREFERENCE_LANDSCAPE_FLIPPED: - result = Qt::InvertedLandscapeOrientation; - break; - case ORIENTATION_PREFERENCE_PORTRAIT_FLIPPED: - result = Qt::InvertedPortraitOrientation; - break; + if (QWindowsContext::user32dll.getDisplayAutoRotationPreferences) { + DWORD orientationPreference = ORIENTATION_PREFERENCE_NONE; + if (QWindowsContext::user32dll.getDisplayAutoRotationPreferences(&orientationPreference)) { + switch (orientationPreference) { + case ORIENTATION_PREFERENCE_NONE: + break; + case ORIENTATION_PREFERENCE_LANDSCAPE: + result = Qt::LandscapeOrientation; + break; + case ORIENTATION_PREFERENCE_PORTRAIT: + result = Qt::PortraitOrientation; + break; + case ORIENTATION_PREFERENCE_LANDSCAPE_FLIPPED: + result = Qt::InvertedLandscapeOrientation; + break; + case ORIENTATION_PREFERENCE_PORTRAIT_FLIPPED: + result = Qt::InvertedPortraitOrientation; + break; + } } } return result; diff --git a/qtbase/src/plugins/platforms/windows/qwindowstheme.cpp b/qtbase/src/plugins/platforms/windows/qwindowstheme.cpp index 4fccec98..e61447a2 100644 --- a/qtbase/src/plugins/platforms/windows/qwindowstheme.cpp +++ b/qtbase/src/plugins/platforms/windows/qwindowstheme.cpp @@ -42,6 +42,8 @@ #include +#include + #if QT_CONFIG(cpp_winrt) # include @@ -243,19 +245,21 @@ static QColor placeHolderColor(QColor textColor) */ static void populateLightSystemBasePalette(QPalette &result) { - const QColor background = getSysColor(COLOR_BTNFACE); - const QColor textColor = getSysColor(COLOR_WINDOWTEXT); + QColor background = getSysColor(COLOR_BTNFACE); + QColor textColor = getSysColor(COLOR_WINDOWTEXT); + QColor accent = qt_accentColor(); + QColor accentDarkest = accent.darker(120 * 120 * 120); #if QT_CONFIG(cpp_winrt) - // respect the Windows 11 accent color - using namespace winrt::Windows::UI::ViewManagement; - const auto settings = UISettings(); + if (IsWindows10OrGreater()) + { + // respect the Windows 11 accent color + using namespace winrt::Windows::UI::ViewManagement; + const auto settings = UISettings(); - const QColor accent = getSysColor(settings.GetColorValue(UIColorType::Accent)); - const QColor accentDarkest = getSysColor(settings.GetColorValue(UIColorType::AccentDark3)); -#else - const QColor accent = qt_accentColor(); - const QColor accentDarkest = accent.darker(120 * 120 * 120); + accent = getSysColor(settings.GetColorValue(UIColorType::Accent)); + accentDarkest = getSysColor(settings.GetColorValue(UIColorType::AccentDark3)); + } #endif const QColor linkColor = accent; @@ -292,39 +296,43 @@ static void populateLightSystemBasePalette(QPalette &result) static void populateDarkSystemBasePalette(QPalette &result) { + QColor foreground = Qt::white; + QColor background = QColor(0x1E, 0x1E, 0x1E); + QColor accent = qt_accentColor(); + QColor accentDark = accent.darker(120); + QColor accentDarker = accentDark.darker(120); + QColor accentDarkest = accentDarker.darker(120); + QColor accentLight = accent.lighter(120); + QColor accentLighter = accentLight.lighter(120); + QColor accentLightest = accentLighter.lighter(120); + #if QT_CONFIG(cpp_winrt) - using namespace winrt::Windows::UI::ViewManagement; - const auto settings = UISettings(); + if (IsWindows10OrGreater()) + { + using namespace winrt::Windows::UI::ViewManagement; + const auto settings = UISettings(); - // We have to craft a palette from these colors. The settings.UIElementColor(UIElementType) API - // returns the old system colors, not the dark mode colors. If the background is black (which it - // usually), then override it with a dark gray instead so that we can go up and down the lightness. - const QColor foreground = getSysColor(settings.GetColorValue(UIColorType::Foreground)); - const QColor background = [&settings]() -> QColor { - auto systemBackground = getSysColor(settings.GetColorValue(UIColorType::Background)); - if (systemBackground == Qt::black) - systemBackground = QColor(0x1E, 0x1E, 0x1E); - return systemBackground; - }(); + // We have to craft a palette from these colors. The settings.UIElementColor(UIElementType) API + // returns the old system colors, not the dark mode colors. If the background is black (which it + // usually), then override it with a dark gray instead so that we can go up and down the lightness. + foreground = getSysColor(settings.GetColorValue(UIColorType::Foreground)); + background = [&settings]() -> QColor { + auto systemBackground = getSysColor(settings.GetColorValue(UIColorType::Background)); + if (systemBackground == Qt::black) + systemBackground = QColor(0x1E, 0x1E, 0x1E); + return systemBackground; + }(); - const QColor accent = getSysColor(settings.GetColorValue(UIColorType::Accent)); - const QColor accentDark = getSysColor(settings.GetColorValue(UIColorType::AccentDark1)); - const QColor accentDarker = getSysColor(settings.GetColorValue(UIColorType::AccentDark2)); - const QColor accentDarkest = getSysColor(settings.GetColorValue(UIColorType::AccentDark3)); - const QColor accentLight = getSysColor(settings.GetColorValue(UIColorType::AccentLight1)); - const QColor accentLighter = getSysColor(settings.GetColorValue(UIColorType::AccentLight2)); - const QColor accentLightest = getSysColor(settings.GetColorValue(UIColorType::AccentLight3)); -#else - const QColor foreground = Qt::white; - const QColor background = QColor(0x1E, 0x1E, 0x1E); - const QColor accent = qt_accentColor(); - const QColor accentDark = accent.darker(120); - const QColor accentDarker = accentDark.darker(120); - const QColor accentDarkest = accentDarker.darker(120); - const QColor accentLight = accent.lighter(120); - const QColor accentLighter = accentLight.lighter(120); - const QColor accentLightest = accentLighter.lighter(120); + accent = getSysColor(settings.GetColorValue(UIColorType::Accent)); + accentDark = getSysColor(settings.GetColorValue(UIColorType::AccentDark1)); + accentDarker = getSysColor(settings.GetColorValue(UIColorType::AccentDark2)); + accentDarkest = getSysColor(settings.GetColorValue(UIColorType::AccentDark3)); + accentLight = getSysColor(settings.GetColorValue(UIColorType::AccentLight1)); + accentLighter = getSysColor(settings.GetColorValue(UIColorType::AccentLight2)); + accentLightest = getSysColor(settings.GetColorValue(UIColorType::AccentLight3)); + } #endif + const QColor linkColor = accent; const QColor buttonColor = background.lighter(200); @@ -551,16 +559,19 @@ void QWindowsTheme::refreshPalettes() m_palettes[MenuPalette] = new QPalette(menuPalette(*m_palettes[SystemPalette], light)); m_palettes[MenuBarPalette] = menuBarPalette(*m_palettes[MenuPalette], light); if (!light) { + QColor accent = qt_accentColor(); + QColor accentLight = accent.lighter(120); + QColor accentDarkest = accent.darker(120 * 120 * 120); + #if QT_CONFIG(cpp_winrt) - using namespace winrt::Windows::UI::ViewManagement; - const auto settings = UISettings(); - const QColor accent = getSysColor(settings.GetColorValue(UIColorType::Accent)); - const QColor accentLight = getSysColor(settings.GetColorValue(UIColorType::AccentLight1)); - const QColor accentDarkest = getSysColor(settings.GetColorValue(UIColorType::AccentDark3)); -#else - const QColor accent = qt_accentColor(); - const QColor accentLight = accent.lighter(120); - const QColor accentDarkest = accent.darker(120 * 120 * 120); + if (IsWindows10OrGreater()) + { + using namespace winrt::Windows::UI::ViewManagement; + const auto settings = UISettings(); + accent = getSysColor(settings.GetColorValue(UIColorType::Accent)); + accentLight = getSysColor(settings.GetColorValue(UIColorType::AccentLight1)); + accentDarkest = getSysColor(settings.GetColorValue(UIColorType::AccentDark3)); + } #endif m_palettes[CheckBoxPalette] = new QPalette(*m_palettes[SystemPalette]); m_palettes[CheckBoxPalette]->setColor(QPalette::Active, QPalette::Base, accent); @@ -664,8 +675,14 @@ void QWindowsTheme::refreshFonts() fixedFont.setStyleHint(QFont::TypeWriter); LOGFONT lfIconTitleFont; - SystemParametersInfoForDpi(SPI_GETICONTITLELOGFONT, sizeof(lfIconTitleFont), &lfIconTitleFont, 0, dpi); - const QFont iconTitleFont = QWindowsFontDatabase::LOGFONT_to_QFont(lfIconTitleFont, dpi); + QFont iconTitleFont; + if (QWindowsContext::user32dll.systemParametersInfoForDpi) { + QWindowsContext::user32dll.systemParametersInfoForDpi(SPI_GETICONTITLELOGFONT, sizeof(lfIconTitleFont), &lfIconTitleFont, 0, dpi); + iconTitleFont = QWindowsFontDatabase::LOGFONT_to_QFont(lfIconTitleFont, dpi); + } else { + SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(lfIconTitleFont), &lfIconTitleFont, 0); + iconTitleFont = QWindowsFontDatabase::LOGFONT_to_QFont(lfIconTitleFont); + } m_fonts[SystemFont] = new QFont(QWindowsFontDatabase::systemDefaultFont()); m_fonts[MenuFont] = new QFont(menuFont); diff --git a/qtbase/src/plugins/platforms/windows/qwindowswindow.cpp b/qtbase/src/plugins/platforms/windows/qwindowswindow.cpp index e7fc6d06..de71c5c3 100644 --- a/qtbase/src/plugins/platforms/windows/qwindowswindow.cpp +++ b/qtbase/src/plugins/platforms/windows/qwindowswindow.cpp @@ -523,11 +523,15 @@ static inline void updateGLWindowSettings(const QWindow *w, HWND hwnd, Qt::Windo [[nodiscard]] static inline int getResizeBorderThickness(const UINT dpi) { - // 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 (QWindowsContext::user32dll.getSystemMetricsForDpi) { + // 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 QWindowsContext::user32dll.getSystemMetricsForDpi(SM_CXSIZEFRAME, dpi) + + QWindowsContext::user32dll.getSystemMetricsForDpi(SM_CXPADDEDBORDER, dpi); + } + + return GetSystemMetrics(SM_CXSIZEFRAME) + GetSystemMetrics(SM_CXPADDEDBORDER); } /*! @@ -537,13 +541,17 @@ static inline void updateGLWindowSettings(const QWindow *w, HWND hwnd, Qt::Windo static QMargins invisibleMargins(QPoint screenPoint) { - POINT pt = {screenPoint.x(), screenPoint.y()}; - if (HMONITOR hMonitor = MonitorFromPoint(pt, MONITOR_DEFAULTTONULL)) { - UINT dpiX; - UINT dpiY; - if (SUCCEEDED(GetDpiForMonitor(hMonitor, MDT_EFFECTIVE_DPI, &dpiX, &dpiY))) { - const int gap = getResizeBorderThickness(dpiX); - return QMargins(gap, 0, gap, gap); + if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows10) { + POINT pt = {screenPoint.x(), screenPoint.y()}; + if (HMONITOR hMonitor = MonitorFromPoint(pt, MONITOR_DEFAULTTONULL)) { + if (QWindowsContext::shcoredll.isValid()) { + UINT dpiX; + UINT dpiY; + if (SUCCEEDED(QWindowsContext::shcoredll.getDpiForMonitor(hMonitor, MDT_EFFECTIVE_DPI, &dpiX, &dpiY))) { + const int gap = getResizeBorderThickness(dpiX); + return QMargins(gap, 0, gap, gap); + } + } } } return QMargins(); @@ -551,9 +559,12 @@ static QMargins invisibleMargins(QPoint screenPoint) [[nodiscard]] static inline QMargins invisibleMargins(const HWND hwnd) { - const UINT dpi = GetDpiForWindow(hwnd); - const int gap = getResizeBorderThickness(dpi); - return QMargins(gap, 0, gap, gap); + if (QWindowsContext::user32dll.getDpiForWindow) { + const UINT dpi = QWindowsContext::user32dll.getDpiForWindow(hwnd); + const int gap = getResizeBorderThickness(dpi); + return QMargins(gap, 0, gap, gap); + } + return QMargins(); } /*! @@ -1054,7 +1065,8 @@ 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 (QWindowsContext::user32dll.adjustWindowRectExForDpi && + QWindowsContext::user32dll.adjustWindowRectExForDpi(&rect, style, FALSE, exStyle, unsigned(qRound(dpi))) == FALSE) { qErrnoWarning("%s: AdjustWindowRectExForDpi failed", __FUNCTION__); } const QMargins result(qAbs(rect.left), qAbs(rect.top), @@ -1548,7 +1560,8 @@ void QWindowsWindow::initialize() QWindowSystemInterface::handleGeometryChange(w, obtainedGeometry); } } - QWindowsWindow::setSavedDpi(GetDpiForWindow(handle())); + QWindowsWindow::setSavedDpi(QWindowsContext::user32dll.getDpiForWindow ? + QWindowsContext::user32dll.getDpiForWindow(handle()) : 96); } QSurfaceFormat QWindowsWindow::format() const @@ -2040,17 +2053,20 @@ void QWindowsWindow::handleDpiChanged(HWND hwnd, WPARAM wParam, LPARAM lParam) void QWindowsWindow::handleDpiChangedAfterParent(HWND hwnd) { - const UINT dpi = GetDpiForWindow(hwnd); - const qreal scale = dpiRelativeScale(dpi); - setSavedDpi(dpi); + if (QWindowsContext::user32dll.getDpiForWindow) + { + const UINT dpi = QWindowsContext::user32dll.getDpiForWindow(hwnd); + const qreal scale = dpiRelativeScale(dpi); + setSavedDpi(dpi); - checkForScreenChanged(QWindowsWindow::FromDpiChange); + checkForScreenChanged(QWindowsWindow::FromDpiChange); - // Child windows do not get WM_GETDPISCALEDSIZE messages to inform - // Windows about the new size, so we need to manually scale them. - QRect currentGeometry = geometry(); - QRect scaledGeometry = QRect(currentGeometry.topLeft() * scale, currentGeometry.size() * scale); - setGeometry(scaledGeometry); + // Child windows do not get WM_GETDPISCALEDSIZE messages to inform + // Windows about the new size, so we need to manually scale them. + QRect currentGeometry = geometry(); + QRect scaledGeometry = QRect(currentGeometry.topLeft() * scale, currentGeometry.size() * scale); + setGeometry(scaledGeometry); + } } static QRect normalFrameGeometry(HWND hwnd)