Source: https://github.com/crystalidea/qt6windows7 Release 6.8.3 diff --git a/src/corelib/io/qstandardpaths_win.cpp b/src/corelib/io/qstandardpaths_win.cpp index 805ce65a5ac..6ed351d2e82 100644 --- a/src/corelib/io/qstandardpaths_win.cpp +++ b/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/src/corelib/kernel/qeventdispatcher_win.cpp b/src/corelib/kernel/qeventdispatcher_win.cpp index a7663b24813..8459cd5cad0 100644 --- a/src/corelib/kernel/qeventdispatcher_win.cpp +++ b/src/corelib/kernel/qeventdispatcher_win.cpp @@ -360,10 +360,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/src/corelib/kernel/qfunctions_win.cpp b/src/corelib/kernel/qfunctions_win.cpp index 048fdbc934c..e715093d27b 100644 --- a/src/corelib/kernel/qfunctions_win.cpp +++ b/src/corelib/kernel/qfunctions_win.cpp @@ -44,10 +44,17 @@ 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)) { + switch (const auto result = myGetCurrentPackageFullName(&length, nullptr)) { case ERROR_INSUFFICIENT_BUFFER: return true; case APPMODEL_ERROR_NO_PACKAGE: @@ -61,6 +68,9 @@ bool qt_win_hasPackageIdentity() #else return false; #endif + } + + return false; } QT_END_NAMESPACE diff --git a/src/corelib/thread/qfutex_p.h b/src/corelib/thread/qfutex_p.h index 8ba798f9209..f6a8dda6b81 100644 --- a/src/corelib/thread/qfutex_p.h +++ b/src/corelib/thread/qfutex_p.h @@ -40,8 +40,8 @@ QT_END_NAMESPACE #elif defined(Q_OS_LINUX) && !defined(QT_LINUXBASE) // use Linux mutexes everywhere except for LSB builds # include "qfutex_linux_p.h" -#elif defined(Q_OS_WIN) -# include "qfutex_win_p.h" +//#elif defined(Q_OS_WIN) +//# include "qfutex_win_p.h" #else QT_BEGIN_NAMESPACE namespace QtFutex = QtDummyFutex; diff --git a/src/corelib/thread/qmutex.cpp b/src/corelib/thread/qmutex.cpp index 1b8f76f1230..9e2fe83968c 100644 --- a/src/corelib/thread/qmutex.cpp +++ b/src/corelib/thread/qmutex.cpp @@ -915,6 +915,8 @@ QT_END_NAMESPACE // nothing #elif defined(Q_OS_DARWIN) # include "qmutex_mac.cpp" +#elif defined(Q_OS_WIN) +# include "qmutex_win.cpp" #else # include "qmutex_unix.cpp" #endif diff --git a/src/corelib/thread/qmutex_p.h b/src/corelib/thread/qmutex_p.h index aabb66fa550..a16d5082154 100644 --- a/src/corelib/thread/qmutex_p.h +++ b/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/src/corelib/thread/qmutex_win.cpp b/src/corelib/thread/qmutex_win.cpp new file mode 100644 index 00000000000..9186f89a341 --- /dev/null +++ b/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/src/corelib/thread/qthread_win.cpp b/src/corelib/thread/qthread_win.cpp index 88ba6dc8f62..c544d972f68 100644 --- a/src/corelib/thread/qthread_win.cpp +++ b/src/corelib/thread/qthread_win.cpp @@ -227,6 +227,62 @@ DWORD WINAPI qt_adopted_thread_watcher_function(LPVOID) return 0; } +#ifndef Q_OS_WIN64 +# define ULONG_PTR DWORD +#endif + +typedef struct tagTHREADNAME_INFO +{ + DWORD dwType; // must be 0x1000 + LPCSTR szName; // pointer to name (in user addr space) + HANDLE dwThreadID; // thread ID (-1=caller thread) + DWORD dwFlags; // reserved for future use, must be zero +} THREADNAME_INFO; + +typedef HRESULT(WINAPI* SetThreadDescriptionFunc)(HANDLE, PCWSTR); + +#if defined(Q_CC_MSVC) + +// Helper function to set the thread name using RaiseException and __try +static void setThreadNameUsingException(HANDLE threadId, LPCSTR threadName) { + THREADNAME_INFO info; + info.dwType = 0x1000; + info.szName = threadName; + info.dwThreadID = threadId; + info.dwFlags = 0; + + __try { + RaiseException(0x406D1388, 0, sizeof(info) / sizeof(DWORD), + reinterpret_cast(&info)); + } + __except (EXCEPTION_CONTINUE_EXECUTION) { + } +} + +#endif // Q_CC_MSVC + +void qt_set_thread_name(HANDLE threadId, const QString &name) +{ + HMODULE hKernel32 = GetModuleHandleW(L"Kernel32.dll"); + + SetThreadDescriptionFunc pSetThreadDescription = + reinterpret_cast(GetProcAddress(hKernel32, "SetThreadDescription")); + + if (pSetThreadDescription) { + pSetThreadDescription(threadId, reinterpret_cast(name.utf16()) ); + } + else { + + #if defined(Q_CC_MSVC) + + std::string stdStr = name.toStdString(); + LPCSTR threadName = stdStr.c_str(); + setThreadNameUsingException(threadId, threadName); + + #endif // Q_CC_MSVC + } +} + /************************************************************************** ** QThreadPrivate *************************************************************************/ @@ -264,7 +320,7 @@ unsigned int __stdcall QT_ENSURE_STACK_ALIGNED_FOR_SSE QThreadPrivate::start(voi QString threadName = std::exchange(thr->d_func()->objectName, {}); if (Q_LIKELY(threadName.isEmpty())) threadName = QString::fromUtf8(thr->metaObject()->className()); - SetThreadDescription(GetCurrentThread(), reinterpret_cast(threadName.utf16())); + qt_set_thread_name(GetCurrentThread(), threadName); emit thr->started(QThread::QPrivateSignal()); QThread::setTerminationEnabled(true); diff --git a/src/gui/rhi/qrhid3d11.cpp b/src/gui/rhi/qrhid3d11.cpp index 9e2e0c4e81c..eae05a0e61a 100644 --- a/src/gui/rhi/qrhid3d11.cpp +++ b/src/gui/rhi/qrhid3d11.cpp @@ -12,6 +12,8 @@ #include +#include + QT_BEGIN_NAMESPACE using namespace Qt::StringLiterals; @@ -184,13 +186,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; } @@ -5103,6 +5114,15 @@ 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. @@ -5427,4 +5447,9 @@ bool QD3D11SwapChain::createOrResize() return true; } +bool QD3D11SwapChain::createOrResizeWin7() +{ + return false; // not implemented yet ;( +} + QT_END_NAMESPACE diff --git a/src/gui/rhi/qrhid3d11_p.h b/src/gui/rhi/qrhid3d11_p.h index 44ad7017d9f..7f232f1ae9c 100644 --- a/src/gui/rhi/qrhid3d11_p.h +++ b/src/gui/rhi/qrhid3d11_p.h @@ -596,6 +596,7 @@ 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, diff --git a/src/gui/rhi/qrhid3d12.cpp b/src/gui/rhi/qrhid3d12.cpp index 0662c53ed65..1039914d57f 100644 --- a/src/gui/rhi/qrhid3d12.cpp +++ b/src/gui/rhi/qrhid3d12.cpp @@ -203,19 +203,35 @@ 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)) { // retry without debug, if it was requested (to match D3D11 backend behavior) if (debugLayer) { qCDebug(QRHI_LOG_INFO, "Debug layer was requested but is not available. " "Attempting to create DXGIFactory2 without it."); factoryFlags &= ~DXGI_CREATE_FACTORY_DEBUG; - hr = CreateDXGIFactory2(factoryFlags, __uuidof(IDXGIFactory2), reinterpret_cast(&dxgiFactory)); + hr = myCreateDXGIFactory2(factoryFlags, __uuidof(IDXGIFactory2), reinterpret_cast(&dxgiFactory)); } if (SUCCEEDED(hr)) { debugLayer = false; @@ -242,7 +258,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(); @@ -310,7 +326,7 @@ bool QRhiD3D12::create(QRhi::Flags flags) if (minimumFeatureLevel == 0) minimumFeatureLevel = MIN_FEATURE_LEVEL; - hr = D3D12CreateDevice(activeAdapter, + hr = myD3D12CreateDevice(activeAdapter, minimumFeatureLevel, __uuidof(ID3D12Device2), reinterpret_cast(&dev)); @@ -2762,6 +2778,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; @@ -2807,8 +2826,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; @@ -4219,7 +4245,7 @@ bool QD3D12Texture::prepareCreate(QSize *adjustedSize) else srvFormat = toD3DTextureFormat(m_readViewFormat.format, m_readViewFormat.srgb ? sRGB : Flags()); } - + mipLevelCount = uint(hasMipMaps ? rhiD->q->mipLevelsForSize(size) : 1); sampleDesc = rhiD->effectiveSampleDesc(m_sampleCount, dxgiFormat); if (sampleDesc.Count > 1) { @@ -5001,6 +5027,9 @@ QD3D12ObjectHandle QD3D12ShaderResourceBindings::createRootSignature(const QD3D1 { QRHI_RES_RHI(QRhiD3D12); + if (!myD3D12SerializeVersionedRootSignature) + return {}; + // It's not just that the root signature has to be tied to the pipeline // (cannot just freely create it like e.g. with Vulkan where one just // creates a descriptor layout 1:1 with the QRhiShaderResourceBindings' @@ -5085,7 +5114,7 @@ QD3D12ObjectHandle QD3D12ShaderResourceBindings::createRootSignature(const QD3D1 rsDesc.Desc_1_1.Flags = D3D12_ROOT_SIGNATURE_FLAGS(rsFlags); 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/src/gui/text/windows/qwindowsfontdatabasebase.cpp b/src/gui/text/windows/qwindowsfontdatabasebase.cpp index 84e619b0d93..e751d4b1fb7 100644 --- a/src/gui/text/windows/qwindowsfontdatabasebase.cpp +++ b/src/gui/text/windows/qwindowsfontdatabasebase.cpp @@ -715,7 +715,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/src/network/kernel/qdnslookup_win.cpp b/src/network/kernel/qdnslookup_win.cpp index 1b07776db9d..5410edab880 100644 --- a/src/network/kernel/qdnslookup_win.cpp +++ b/src/network/kernel/qdnslookup_win.cpp @@ -5,11 +5,9 @@ #include #include "qdnslookup_p.h" -#include +#include #include #include -#include -#include #include #include @@ -65,100 +63,103 @@ DNS_STATUS WINAPI DnsQueryEx(PDNS_QUERY_REQUEST pQueryRequest, QT_BEGIN_NAMESPACE -static DNS_STATUS sendAlternate(QDnsLookupRunnable *self, QDnsLookupReply *reply, - PDNS_QUERY_REQUEST request, PDNS_QUERY_RESULT results) -{ - // WinDNS wants MTU - IP Header - UDP header for some reason, in spite - // of never needing that much - QVarLengthArray query(1472); - - auto dnsBuffer = new (query.data()) DNS_MESSAGE_BUFFER; - DWORD dnsBufferSize = query.size(); - WORD xid = 0; - bool recursionDesired = true; - - SetLastError(ERROR_SUCCESS); - - // MinGW winheaders incorrectly declare the third parameter as LPWSTR - if (!DnsWriteQuestionToBuffer_W(dnsBuffer, &dnsBufferSize, - const_cast(request->QueryName), request->QueryType, - xid, recursionDesired)) { - // let's try reallocating - query.resize(dnsBufferSize); - if (!DnsWriteQuestionToBuffer_W(dnsBuffer, &dnsBufferSize, - const_cast(request->QueryName), request->QueryType, - xid, recursionDesired)) { - return GetLastError(); - } - } - - // set AD bit: we want to trust this server - dnsBuffer->MessageHead.AuthenticatedData = true; - - QDnsLookupRunnable::ReplyBuffer replyBuffer; - if (!self->sendDnsOverTls(reply, { query.data(), qsizetype(dnsBufferSize) }, replyBuffer)) - return DNS_STATUS(-1); // error set in reply - - // interpret the RCODE in the reply - auto response = reinterpret_cast(replyBuffer.data()); - DNS_HEADER *header = &response->MessageHead; - if (!header->IsResponse) - return DNS_ERROR_BAD_PACKET; // not a reply - - // Convert the byte order for the 16-bit quantities in the header, so - // DnsExtractRecordsFromMessage can parse the contents. - //header->Xid = qFromBigEndian(header->Xid); - header->QuestionCount = qFromBigEndian(header->QuestionCount); - header->AnswerCount = qFromBigEndian(header->AnswerCount); - header->NameServerCount = qFromBigEndian(header->NameServerCount); - header->AdditionalCount = qFromBigEndian(header->AdditionalCount); - - results->QueryOptions = request->QueryOptions; - return DnsExtractRecordsFromMessage_W(response, replyBuffer.size(), &results->pQueryRecords); -} - 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"); + + 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; + } - if (protocol == QDnsLookup::Standard && !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; + } - DNS_QUERY_RESULT results = {}; - results.Version = 1; - DNS_STATUS status = ERROR_INVALID_PARAMETER; - switch (protocol) { - case QDnsLookup::Standard: - status = DnsQueryEx(&request, &results, nullptr); - break; - case QDnsLookup::DnsOverTls: - status = sendAlternate(this, reply, &request, &results); - break; + ptrStart = dns_records; } - if (status == DNS_STATUS(-1)) - return; // error already set in reply - 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; @@ -170,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) { @@ -224,25 +225,6 @@ void QDnsLookupRunnable::query(QDnsLookupReply *reply) record.d->timeToLive = ptr->dwTtl; record.d->weight = ptr->Data.Srv.wWeight; reply->serviceRecords.append(record); - } else if (ptr->wType == QDnsLookup::TLSA) { - // Note: untested, because the DNS_RECORD reply appears to contain - // no records relating to TLSA. Maybe WinDNS filters them out of - // zones without DNSSEC. - QDnsTlsAssociationRecord record; - record.d->name = name; - record.d->timeToLive = ptr->dwTtl; - - const auto &tlsa = ptr->Data.Tlsa; - const quint8 usage = tlsa.bCertUsage; - const quint8 selector = tlsa.bSelector; - const quint8 matchType = tlsa.bMatchingType; - - record.d->usage = QDnsTlsAssociationRecord::CertificateUsage(usage); - record.d->selector = QDnsTlsAssociationRecord::Selector(selector); - record.d->matchType = QDnsTlsAssociationRecord::MatchingType(matchType); - record.d->value.assign(tlsa.bCertificateAssociationData, - tlsa.bCertificateAssociationData + tlsa.bCertificateAssociationDataLength); - reply->tlsAssociationRecords.append(std::move(record)); } else if (ptr->wType == QDnsLookup::TXT) { QDnsTextRecord record; record.d->name = name; @@ -254,7 +236,7 @@ void QDnsLookupRunnable::query(QDnsLookupReply *reply) } } - DnsRecordListFree(results.pQueryRecords, DnsFreeRecordList); + DnsRecordListFree(ptrStart, DnsFreeRecordList); } QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwin10helpers.cpp b/src/plugins/platforms/windows/qwin10helpers.cpp index 026e81cb0c7..3bbc974b744 100644 --- a/src/plugins/platforms/windows/qwin10helpers.cpp +++ b/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 (void *) ::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; - - 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(&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(); + 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); + + WindowsCreateStringReference_t WindowsCreateStringReferenceFunc = (WindowsCreateStringReference_t)WIN_LoadComBaseFunction("WindowsCreateStringReference"); + RoGetActivationFactory_t RoGetActivationFactoryFunc = (RoGetActivationFactory_t)WIN_LoadComBaseFunction("RoGetActivationFactory"); + + if (WindowsCreateStringReferenceFunc && RoGetActivationFactoryFunc) + { + 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(WindowsCreateStringReferenceFunc(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 = 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/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp index 88e9da5557c..7df58793707 100644 --- a/src/plugins/platforms/windows/qwindowscontext.cpp +++ b/src/plugins/platforms/windows/qwindowscontext.cpp @@ -43,6 +43,7 @@ #include #include #include +#include #include #if QT_CONFIG(cpp_winrt) # include @@ -59,6 +60,8 @@ #include #include +#include "vxkex.h" + QT_BEGIN_NAMESPACE using namespace Qt::StringLiterals; @@ -120,6 +123,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; /*! @@ -160,6 +234,9 @@ bool QWindowsContextPrivate::m_v2DpiAware = false; QWindowsContextPrivate::QWindowsContextPrivate() : m_oleInitializeResult(OleInitialize(nullptr)) { + QWindowsContext::user32dll.init(); + QWindowsContext::shcoredll.init(); + if (m_pointerHandler.touchDevice()) m_systemInfo |= QWindowsContext::SI_SupportsTouch; m_displayContext = GetDC(nullptr); @@ -338,19 +415,39 @@ 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)) - 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; + 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; + } + else + { + // IsValidDpiAwarenessContext() will handle the NULL pointer case. + if (!vxkex::IsValidDpiAwarenessContext(context)) + return QtWindows::DpiAwareness::Invalid; + if (vxkex::AreDpiAwarenessContextsEqual(context, DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED)) + return QtWindows::DpiAwareness::Unaware_GdiScaled; + if (vxkex::AreDpiAwarenessContextsEqual(context, DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2)) + return QtWindows::DpiAwareness::PerMonitorVersion2; + if (vxkex::AreDpiAwarenessContextsEqual(context, DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE)) + return QtWindows::DpiAwareness::PerMonitor; + if (vxkex::AreDpiAwarenessContextsEqual(context, DPI_AWARENESS_CONTEXT_SYSTEM_AWARE)) + return QtWindows::DpiAwareness::System; + if (vxkex::AreDpiAwarenessContextsEqual(context, DPI_AWARENESS_CONTEXT_UNAWARE)) + return QtWindows::DpiAwareness::Unaware; + } + return QtWindows::DpiAwareness::Invalid; } @@ -358,7 +455,11 @@ QtWindows::DpiAwareness QWindowsContext::windowDpiAwareness(HWND hwnd) { if (!hwnd) return QtWindows::DpiAwareness::Invalid; - const auto context = GetWindowDpiAwarenessContext(hwnd); + + const auto context = QWindowsContext::user32dll.getWindowDpiAwarenessContext ? + QWindowsContext::user32dll.getWindowDpiAwarenessContext(hwnd) : + vxkex::GetWindowDpiAwarenessContext(hwnd); + return dpiAwarenessContextToQtDpiAwareness(context); } @@ -371,7 +472,9 @@ QtWindows::DpiAwareness QWindowsContext::processDpiAwareness() // 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(); + const DPI_AWARENESS_CONTEXT context = QWindowsContext::user32dll.getThreadDpiAwarenessContext ? + QWindowsContext::user32dll.getThreadDpiAwarenessContext() : + vxkex::GetThreadDpiAwarenessContext(); return dpiAwarenessContextToQtDpiAwareness(context); } @@ -431,11 +534,21 @@ bool QWindowsContext::setProcessDpiAwareness(QtWindows::DpiAwareness dpiAwarenes if (processDpiAwareness() == dpiAwareness) return true; const auto context = qtDpiAwarenessToDpiAwarenessContext(dpiAwareness); - if (!IsValidDpiAwarenessContext(context)) { + + BOOL bResultIsValid = QWindowsContext::user32dll.isValidDpiAwarenessContext ? + QWindowsContext::user32dll.isValidDpiAwarenessContext(context) : + vxkex::IsValidDpiAwarenessContext(context); + + if (!bResultIsValid) { qCWarning(lcQpaWindow) << dpiAwareness << "is not supported by current system."; return false; } - if (!SetProcessDpiAwarenessContext(context)) { + + BOOL bResultSet = QWindowsContext::user32dll.setProcessDpiAwarenessContext ? + QWindowsContext::user32dll.setProcessDpiAwarenessContext(context) : + vxkex::SetProcessDpiAwarenessContext(context); + + if (!bResultSet) { qCWarning(lcQpaWindow).noquote().nospace() << "SetProcessDpiAwarenessContext() failed: " << QSystemError::windowsString() @@ -868,9 +981,9 @@ 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) - : SystemParametersInfo(action, param, out, 0); + const BOOL result = (QWindowsContext::user32dll.systemParametersInfoForDpi != nullptr && dpi != 0) + ? QWindowsContext::user32dll.systemParametersInfoForDpi(action, param, out, 0, dpi) + : vxkex::SystemParametersInfoForDpi(action, param, out, 0, dpi); return result == TRUE; } @@ -957,7 +1070,10 @@ static bool enableNonClientDpiScaling(HWND hwnd) { bool result = false; if (QWindowsContext::windowDpiAwareness(hwnd) == QtWindows::DpiAwareness::PerMonitor) { - result = EnableNonClientDpiScaling(hwnd) != FALSE; + result = QWindowsContext::user32dll.enableNonClientDpiScaling ? + (QWindowsContext::user32dll.enableNonClientDpiScaling(hwnd) != FALSE) : + (vxkex::EnableNonClientDpiScaling(hwnd) != FALSE); + if (!result) { const DWORD errorCode = GetLastError(); qErrnoWarning(int(errorCode), "EnableNonClientDpiScaling() failed for HWND %p (%lu)", diff --git a/src/plugins/platforms/windows/qwindowscontext.h b/src/plugins/platforms/windows/qwindowscontext.h index 4e9be1af967..357f7839353 100644 --- a/src/plugins/platforms/windows/qwindowscontext.h +++ b/src/plugins/platforms/windows/qwindowscontext.h @@ -14,6 +14,7 @@ #define STRICT_TYPED_ITEMIDS #include #include +#include QT_BEGIN_NAMESPACE @@ -44,6 +45,95 @@ struct QWindowsContextPrivate; 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) @@ -134,6 +224,9 @@ public: QWindowsScreenManager &screenManager(); QWindowsTabletSupport *tabletSupport() const; + static QWindowsUser32DLL user32dll; + static QWindowsShcoreDLL shcoredll; + bool asyncExpose() const; void setAsyncExpose(bool value); diff --git a/src/plugins/platforms/windows/qwindowsdrag.cpp b/src/plugins/platforms/windows/qwindowsdrag.cpp index 5d3a47c22fd..563b22a831f 100644 --- a/src/plugins/platforms/windows/qwindowsdrag.cpp +++ b/src/plugins/platforms/windows/qwindowsdrag.cpp @@ -33,6 +33,8 @@ #include +#include "vxkex.h" + QT_BEGIN_NAMESPACE /*! @@ -674,7 +676,11 @@ static HRESULT startDoDragDrop(LPDATAOBJECT pDataObj, LPDROPSOURCE pDropSource, const quint32 pointerId = GET_POINTERID_WPARAM(msg.wParam); POINTER_INFO pointerInfo{}; - if (!GetPointerInfo(pointerId, &pointerInfo)) + BOOL bResultPointerInfo = QWindowsContext::user32dll.getPointerInfo ? + QWindowsContext::user32dll.getPointerInfo(pointerId, &pointerInfo) : + vxkex::GetPointerInfo(pointerId, &pointerInfo); + + if (!bResultPointerInfo) return E_FAIL; if (pointerInfo.pointerFlags & POINTER_FLAG_PRIMARY) { diff --git a/src/plugins/platforms/windows/qwindowsintegration.cpp b/src/plugins/platforms/windows/qwindowsintegration.cpp index a9fcf711edd..3a08bd35363 100644 --- a/src/plugins/platforms/windows/qwindowsintegration.cpp +++ b/src/plugins/platforms/windows/qwindowsintegration.cpp @@ -140,6 +140,7 @@ static inline unsigned parseOptions(const QStringList ¶mList, DarkModeHandling *darkModeHandling) { unsigned options = 0; + for (const QString ¶m : paramList) { if (param.startsWith(u"fontengine=")) { if (param.endsWith(u"gdi")) { @@ -485,7 +486,14 @@ QPlatformFontDatabase *QWindowsIntegration::fontDatabase() const else #endif // QT_NO_FREETYPE #if QT_CONFIG(directwrite3) - if (!(d->m_options & (QWindowsIntegration::FontDatabaseGDI | QWindowsIntegration::DontUseDirectWriteFonts))) + + /* IDWriteFontFace3 is only reportedly available starting with Windows 10. This change is necessary starting + with Qt 6.8, where DirectWrite is used by default to populate the font database. + More info: https://github.com/videolan/vlc/blob/master/contrib/src/qt/0001-Use-DirectWrite-font-database-only-with-Windows-10-a.patch + */ + + if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows10 && + !(d->m_options & (QWindowsIntegration::FontDatabaseGDI | QWindowsIntegration::DontUseDirectWriteFonts))) d->m_fontDatabase = new QWindowsDirectWriteFontDatabase; else #endif diff --git a/src/plugins/platforms/windows/qwindowskeymapper.cpp b/src/plugins/platforms/windows/qwindowskeymapper.cpp index 5b8e4e58ffe..5c84b47794e 100644 --- a/src/plugins/platforms/windows/qwindowskeymapper.cpp +++ b/src/plugins/platforms/windows/qwindowskeymapper.cpp @@ -17,6 +17,8 @@ #include #include +#include "vxkex.h" + #if defined(WM_APPCOMMAND) # ifndef FAPPCOMMAND_MOUSE # define FAPPCOMMAND_MOUSE 0x8000 @@ -732,14 +734,17 @@ 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); + const BOOL bNewAPI = (QWindowsContext::user32dll.getSystemMetricsForDpi != nullptr); + const UINT dpi = bNewAPI ? QWindowsContext::user32dll.getDpiForWindow(hwnd) : vxkex::GetDpiForWindow(hwnd); + const int captionHeight = bNewAPI ? QWindowsContext::user32dll.getSystemMetricsForDpi(SM_CYCAPTION, dpi) : vxkex::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); + const int frameHeight = bNewAPI ? + (QWindowsContext::user32dll.getSystemMetricsForDpi(SM_CYSIZEFRAME, dpi) + QWindowsContext::user32dll.getSystemMetricsForDpi(SM_CXPADDEDBORDER, dpi)) + : (vxkex::GetSystemMetricsForDpi(SM_CYSIZEFRAME, dpi) + vxkex::GetSystemMetricsForDpi(SM_CXPADDEDBORDER, dpi)); + return captionHeight + frameHeight; } diff --git a/src/plugins/platforms/windows/qwindowspointerhandler.cpp b/src/plugins/platforms/windows/qwindowspointerhandler.cpp index 7995716444a..fab22b394ab 100644 --- a/src/plugins/platforms/windows/qwindowspointerhandler.cpp +++ b/src/plugins/platforms/windows/qwindowspointerhandler.cpp @@ -26,6 +26,8 @@ #include +#include "vxkex.h" + QT_BEGIN_NAMESPACE enum { @@ -55,7 +57,11 @@ bool QWindowsPointerHandler::translatePointerEvent(QWindow *window, HWND hwnd, Q *result = 0; const quint32 pointerId = GET_POINTERID_WPARAM(msg.wParam); - if (!GetPointerType(pointerId, &m_pointerType)) { + BOOL bResultPt = QWindowsContext::user32dll.getPointerType ? + QWindowsContext::user32dll.getPointerType(pointerId, &m_pointerType) : + vxkex::GetPointerType(pointerId, &m_pointerType); + + if (!bResultPt) { qWarning() << "GetPointerType() failed:" << qt_error_string(); return false; } @@ -69,12 +75,21 @@ bool QWindowsPointerHandler::translatePointerEvent(QWindow *window, HWND hwnd, Q } case QT_PT_TOUCH: { quint32 pointerCount = 0; - if (!GetPointerFrameTouchInfo(pointerId, &pointerCount, nullptr)) { + BOOL bResultPointerTouchInfo = QWindowsContext::user32dll.getPointerFrameTouchInfo ? + QWindowsContext::user32dll.getPointerFrameTouchInfo(pointerId, &pointerCount, nullptr) : + vxkex::GetPointerFrameTouchInfo(pointerId, &pointerCount, nullptr); + + if (!bResultPointerTouchInfo) { qWarning() << "GetPointerFrameTouchInfo() failed:" << qt_error_string(); return false; } QVarLengthArray touchInfo(pointerCount); - if (!GetPointerFrameTouchInfo(pointerId, &pointerCount, touchInfo.data())) { + + bResultPointerTouchInfo = QWindowsContext::user32dll.getPointerFrameTouchInfo ? + QWindowsContext::user32dll.getPointerFrameTouchInfo(pointerId, &pointerCount, touchInfo.data()) : + vxkex::GetPointerFrameTouchInfo(pointerId, &pointerCount, touchInfo.data()); + + if (!bResultPointerTouchInfo) { qWarning() << "GetPointerFrameTouchInfo() failed:" << qt_error_string(); return false; } @@ -87,10 +102,12 @@ 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())) { + + BOOL bResultTouchHistory = QWindowsContext::user32dll.getPointerFrameTouchInfoHistory ? + QWindowsContext::user32dll.getPointerFrameTouchInfoHistory(pointerId, &historyCount, &pointerCount, touchInfo.data()) : + vxkex::GetPointerFrameTouchInfoHistory(pointerId, &historyCount, &pointerCount, touchInfo.data()); + + if (!bResultTouchHistory) { qWarning() << "GetPointerFrameTouchInfoHistory() failed:" << qt_error_string(); return false; } @@ -108,7 +125,11 @@ bool QWindowsPointerHandler::translatePointerEvent(QWindow *window, HWND hwnd, Q } case QT_PT_PEN: { POINTER_PEN_INFO penInfo; - if (!GetPointerPenInfo(pointerId, &penInfo)) { + + BOOL bResultPenInfo = QWindowsContext::user32dll.getPointerPenInfo ? + QWindowsContext::user32dll.getPointerPenInfo(pointerId, &penInfo) : vxkex::GetPointerPenInfo(pointerId, &penInfo); + + if (!bResultPenInfo) { qWarning() << "GetPointerPenInfo() failed:" << qt_error_string(); return false; } @@ -120,7 +141,11 @@ bool QWindowsPointerHandler::translatePointerEvent(QWindow *window, HWND hwnd, Q || !QCoreApplication::testAttribute(Qt::AA_CompressTabletEvents))) { QVarLengthArray penInfoHistory(historyCount); - if (!GetPointerPenInfoHistory(pointerId, &historyCount, penInfoHistory.data())) { + BOOL bResultPenInfoHistory = QWindowsContext::user32dll.getPointerPenInfoHistory ? + QWindowsContext::user32dll.getPointerPenInfoHistory(pointerId, &historyCount, penInfoHistory.data()) : + vxkex::GetPointerPenInfoHistory(pointerId, &historyCount, penInfoHistory.data()); + + if (!bResultPenInfoHistory) { qWarning() << "GetPointerPenInfoHistory() failed:" << qt_error_string(); return false; } @@ -527,7 +552,10 @@ 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); + if (QWindowsContext::user32dll.skipPointerFrameMessages) + QWindowsContext::user32dll.skipPointerFrameMessages(touchInfo[i].pointerInfo.pointerId); + else + vxkex::SkipPointerFrameMessages(touchInfo[i].pointerInfo.pointerId); } // Some devices send touches for each finger in a different message/frame, instead of consolidating @@ -574,7 +602,12 @@ bool QWindowsPointerHandler::translatePenEvent(QWindow *window, HWND hwnd, QtWin auto *penInfo = static_cast(vPenInfo); RECT pRect, dRect; - if (!GetPointerDeviceRects(penInfo->pointerInfo.sourceDevice, &pRect, &dRect)) + + BOOL bResultDeviceRects = QWindowsContext::user32dll.getPointerDeviceRects ? + QWindowsContext::user32dll.getPointerDeviceRects(penInfo->pointerInfo.sourceDevice, &pRect, &dRect) : + vxkex::GetPointerDeviceRects(penInfo->pointerInfo.sourceDevice, &pRect, &dRect); + + if (!bResultDeviceRects) return false; const auto systemId = (qint64)penInfo->pointerInfo.sourceDevice; diff --git a/src/plugins/platforms/windows/qwindowsscreen.cpp b/src/plugins/platforms/windows/qwindowsscreen.cpp index 6c86c47caac..24588473185 100644 --- a/src/plugins/platforms/windows/qwindowsscreen.cpp +++ b/src/plugins/platforms/windows/qwindowsscreen.cpp @@ -32,6 +32,8 @@ #include #include +#include "vxkex.h" + QT_BEGIN_NAMESPACE using namespace Qt::StringLiterals; @@ -45,7 +47,15 @@ static inline QDpi monitorDPI(HMONITOR hMonitor) { UINT dpiX; UINT dpiY; - if (SUCCEEDED(GetDpiForMonitor(hMonitor, MDT_EFFECTIVE_DPI, &dpiX, &dpiY))) + + HRESULT hr = S_OK; + + if (QWindowsContext::shcoredll.isValid()) + hr = QWindowsContext::shcoredll.getDpiForMonitor(hMonitor, MDT_EFFECTIVE_DPI, &dpiX, &dpiY); + else + hr = vxkex::GetDpiForMonitor(hMonitor, MDT_EFFECTIVE_DPI, &dpiX, &dpiY); + + if (SUCCEEDED(hr)) return QDpi(dpiX, dpiY); return {0, 0}; } @@ -609,7 +619,10 @@ bool QWindowsScreen::setOrientationPreference(Qt::ScreenOrientation o) orientationPreference = ORIENTATION_PREFERENCE_LANDSCAPE_FLIPPED; break; } - result = SetDisplayAutoRotationPreferences(orientationPreference); + if (QWindowsContext::user32dll.setDisplayAutoRotationPreferences) + result = QWindowsContext::user32dll.setDisplayAutoRotationPreferences(orientationPreference); + else + result = vxkex::SetDisplayAutoRotationPreferences(orientationPreference); return result; } @@ -617,7 +630,15 @@ Qt::ScreenOrientation QWindowsScreen::orientationPreference() { Qt::ScreenOrientation result = Qt::PrimaryOrientation; ORIENTATION_PREFERENCE orientationPreference = ORIENTATION_PREFERENCE_NONE; - if (GetDisplayAutoRotationPreferences(&orientationPreference)) { + + BOOL bResult = TRUE; + + if (QWindowsContext::user32dll.getDisplayAutoRotationPreferences) + bResult = QWindowsContext::user32dll.getDisplayAutoRotationPreferences((DWORD *)&orientationPreference); + else + bResult = vxkex::GetDisplayAutoRotationPreferences(&orientationPreference); + + if (bResult) { switch (orientationPreference) { case ORIENTATION_PREFERENCE_NONE: break; diff --git a/src/plugins/platforms/windows/qwindowstheme.cpp b/src/plugins/platforms/windows/qwindowstheme.cpp index 97b2dd339be..2d6dbf36adc 100644 --- a/src/plugins/platforms/windows/qwindowstheme.cpp +++ b/src/plugins/platforms/windows/qwindowstheme.cpp @@ -45,6 +45,8 @@ #include +#include "vxkex.h" + #if QT_CONFIG(cpp_winrt) # include @@ -97,36 +99,52 @@ static constexpr QColor getSysColor(winrt::Windows::UI::Color &&color) [[maybe_unused]] [[nodiscard]] static inline QColor qt_accentColor(AccentColorLevel level) { + QColor accent; + QColor accentLight; + QColor accentLighter; + QColor accentLightest; + QColor accentDark; + QColor accentDarker; + QColor accentDarkest; + #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 accentLighter = getSysColor(settings.GetColorValue(UIColorType::AccentLight2)); - const QColor accentLightest = getSysColor(settings.GetColorValue(UIColorType::AccentLight3)); - const QColor accentDark = getSysColor(settings.GetColorValue(UIColorType::AccentDark1)); - const QColor accentDarker = getSysColor(settings.GetColorValue(UIColorType::AccentDark2)); - const QColor accentDarkest = getSysColor(settings.GetColorValue(UIColorType::AccentDark3)); -#else - const QWinRegistryKey registry(HKEY_CURRENT_USER, LR"(Software\Microsoft\Windows\DWM)"); - if (!registry.isValid()) - return {}; - const QVariant value = registry.value(L"AccentColor"); - if (!value.isValid()) - return {}; - // The retrieved value is in the #AABBGGRR format, we need to - // convert it to the #AARRGGBB format which Qt expects. - const QColor abgr = QColor::fromRgba(qvariant_cast(value)); - if (!abgr.isValid()) - return {}; - const QColor accent = QColor::fromRgb(abgr.blue(), abgr.green(), abgr.red(), abgr.alpha()); - const QColor accentLight = accent.lighter(120); - const QColor accentLighter = accentLight.lighter(120); - const QColor accentLightest = accentLighter.lighter(120); - const QColor accentDark = accent.darker(120); - const QColor accentDarker = accentDark.darker(120); - const QColor accentDarkest = accentDarker.darker(120); + if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows10) + { + using namespace winrt::Windows::UI::ViewManagement; + const auto settings = UISettings(); + accent = getSysColor(settings.GetColorValue(UIColorType::Accent)); + accentLight = getSysColor(settings.GetColorValue(UIColorType::AccentLight1)); + accentLighter = getSysColor(settings.GetColorValue(UIColorType::AccentLight2)); + accentLightest = getSysColor(settings.GetColorValue(UIColorType::AccentLight3)); + accentDark = getSysColor(settings.GetColorValue(UIColorType::AccentDark1)); + accentDarker = getSysColor(settings.GetColorValue(UIColorType::AccentDark2)); + accentDarkest = getSysColor(settings.GetColorValue(UIColorType::AccentDark3)); + } #endif + + if (!accent.isValid()) + { + const QWinRegistryKey registry(HKEY_CURRENT_USER, LR"(Software\Microsoft\Windows\DWM)"); + if (!registry.isValid()) + return {}; + const QVariant value = registry.value(L"AccentColor"); + if (!value.isValid()) + return {}; + // The retrieved value is in the #AABBGGRR format, we need to + // convert it to the #AARRGGBB format which Qt expects. + const QColor abgr = QColor::fromRgba(qvariant_cast(value)); + if (!abgr.isValid()) + return {}; + accent = QColor::fromRgb(abgr.blue(), abgr.green(), abgr.red(), abgr.alpha()); + accentLight = accent.lighter(120); + accentLighter = accentLight.lighter(120); + accentLightest = accentLighter.lighter(120); + accentDarkest = accent.darker(120 * 120 * 120); + accentDark = accent.darker(120); + accentDarker = accentDark.darker(120); + accentDarkest = accentDarker.darker(120); + } + switch (level) { case AccentColorDarkest: return accentDarkest; @@ -154,6 +172,7 @@ static inline QColor getSysColor(int index) // QTBUG-48823/Windows 10: SHGetFileInfo() (as called by item views on file system // models has been observed to trigger a WM_PAINT on the mainwindow. Suppress the // behavior by running it in a thread. + class QShGetFileInfoThread : public QThread { public: @@ -326,46 +345,45 @@ void QWindowsTheme::populateLightSystemBasePalette(QPalette &result) void QWindowsTheme::populateDarkSystemBasePalette(QPalette &result) { - QColor foreground, background, - accent, accentDark, accentDarker, accentDarkest, - accentLight, accentLighter, accentLightest; + QColor foreground = Qt::white; + QColor background = QColor(0x1E, 0x1E, 0x1E); + QColor accent = qt_accentColor(AccentColorNormal); + 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(); - - // 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. - if (QWindowsTheme::queryColorScheme() == Qt::ColorScheme::Dark) { - // the system is actually running in dark mode, so UISettings will give us dark colors - 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; - }(); - accent = qt_accentColor(AccentColorNormal); - accentDark = qt_accentColor(AccentColorDark); - accentDarker = qt_accentColor(AccentColorDarker); - accentDarkest = qt_accentColor(AccentColorDarkest); - accentLight = qt_accentColor(AccentColorLight); - accentLighter = qt_accentColor(AccentColorLighter); - accentLightest = qt_accentColor(AccentColorLightest); - } else -#endif + if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows10) { - // If the system is running in light mode, then we need to make up our own dark palette - foreground = Qt::white; - background = QColor(0x1E, 0x1E, 0x1E); - accent = qt_accentColor(AccentColorNormal); - accentDark = accent.darker(120); - accentDarker = accentDark.darker(120); - accentDarkest = accentDarker.darker(120); - accentLight = accent.lighter(120); - accentLighter = accentLight.lighter(120); - accentLightest = accentLighter.lighter(120); + 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. + if (QWindowsTheme::queryColorScheme() == Qt::ColorScheme::Dark) { + // the system is actually running in dark mode, so UISettings will give us dark colors + 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; + }(); + accent = qt_accentColor(AccentColorNormal); + accentDark = qt_accentColor(AccentColorDark); + accentDarker = qt_accentColor(AccentColorDarker); + accentDarkest = qt_accentColor(AccentColorDarkest); + accentLight = qt_accentColor(AccentColorLight); + accentLighter = qt_accentColor(AccentColorLighter); + accentLightest = qt_accentColor(AccentColorLightest); + } } +#endif + const QColor linkColor = accentLightest; const QColor buttonColor = background.lighter(200); @@ -738,7 +756,10 @@ void QWindowsTheme::refreshFonts() fixedFont.setStyleHint(QFont::TypeWriter); LOGFONT lfIconTitleFont; - SystemParametersInfoForDpi(SPI_GETICONTITLELOGFONT, sizeof(lfIconTitleFont), &lfIconTitleFont, 0, dpi); + if (QWindowsContext::user32dll.systemParametersInfoForDpi) + QWindowsContext::user32dll.systemParametersInfoForDpi(SPI_GETICONTITLELOGFONT, sizeof(lfIconTitleFont), &lfIconTitleFont, 0, dpi); + else + vxkex::SystemParametersInfoForDpi(SPI_GETICONTITLELOGFONT, sizeof(lfIconTitleFont), &lfIconTitleFont, 0, dpi); const QFont iconTitleFont = QWindowsFontDatabase::LOGFONT_to_QFont(lfIconTitleFont, dpi); m_fonts[SystemFont] = new QFont(QWindowsFontDatabase::systemDefaultFont()); @@ -1001,6 +1022,7 @@ public: static QPixmap pixmapFromShellImageList(int iImageList, int iIcon) { QPixmap result; + // For MinGW: static const IID iID_IImageList = {0x46eb5926, 0x582e, 0x4017, {0x9f, 0xdf, 0xe8, 0x99, 0x8d, 0xaa, 0x9, 0x50}}; @@ -1015,6 +1037,7 @@ static QPixmap pixmapFromShellImageList(int iImageList, int iIcon) DestroyIcon(hIcon); } imageList->Release(); + return result; } diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp index f44a28f5636..6d6409c7878 100644 --- a/src/plugins/platforms/windows/qwindowswindow.cpp +++ b/src/plugins/platforms/windows/qwindowswindow.cpp @@ -46,6 +46,8 @@ #include +#include "vxkex.h" + QT_BEGIN_NAMESPACE using QWindowCreationContextPtr = QSharedPointer; @@ -522,11 +524,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); + } + else + return vxkex::GetSystemMetricsForDpi(SM_CXSIZEFRAME, dpi) + vxkex::GetSystemMetricsForDpi(SM_CXPADDEDBORDER, dpi); } /*! @@ -538,11 +544,21 @@ 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 (QWindowsContext::shcoredll.isValid()) { + UINT dpiX; + UINT dpiY; + + HRESULT hr = S_OK; + + if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows10) + hr = QWindowsContext::shcoredll.getDpiForMonitor(hMonitor, MDT_EFFECTIVE_DPI, &dpiX, &dpiY); + else + hr = vxkex::GetDpiForMonitor(hMonitor, MDT_EFFECTIVE_DPI, &dpiX, &dpiY); + + if (SUCCEEDED(hr)) { + const int gap = getResizeBorderThickness(dpiX); + return QMargins(gap, 0, gap, gap); + } } } return QMargins(); @@ -550,7 +566,8 @@ static QMargins invisibleMargins(QPoint screenPoint) [[nodiscard]] static inline QMargins invisibleMargins(const HWND hwnd) { - const UINT dpi = GetDpiForWindow(hwnd); + const UINT dpi = (QWindowsContext::user32dll.getDpiForWindow) ? QWindowsContext::user32dll.getDpiForWindow(hwnd) : vxkex::GetDpiForWindow(hwnd); + const int gap = getResizeBorderThickness(dpi); return QMargins(gap, 0, gap, gap); } @@ -851,7 +868,7 @@ static inline bool shouldApplyDarkFrame(const QWindow *w) { if (!w->isTopLevel() || w->flags().testFlag(Qt::FramelessWindowHint)) return false; - + // the user of the application has explicitly opted out of dark frames if (!QWindowsIntegration::instance()->darkModeHandling().testFlag(QWindowsApplication::DarkModeWindowFrames)) return false; @@ -1071,9 +1088,17 @@ 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) { - qErrnoWarning("%s: AdjustWindowRectExForDpi failed", __FUNCTION__); + if (QWindowsContext::user32dll.adjustWindowRectExForDpi) + { + if (QWindowsContext::user32dll.adjustWindowRectExForDpi(&rect, style, FALSE, exStyle, unsigned(qRound(dpi))) == FALSE) + qErrnoWarning("%s: AdjustWindowRectExForDpi failed", __FUNCTION__); + } + else + { + if (vxkex::AdjustWindowRectExForDpi(&rect, style, FALSE, exStyle, unsigned(qRound(dpi))) == FALSE) + qErrnoWarning("%s: vxkex::AdjustWindowRectExForDpi failed", __FUNCTION__); } + const QMargins result(qAbs(rect.left), qAbs(rect.top), qAbs(rect.right), qAbs(rect.bottom)); qCDebug(lcQpaWindow).nospace() << __FUNCTION__ << " style=" @@ -1380,7 +1405,7 @@ void QWindowsForeignWindow::setParent(const QPlatformWindow *newParentWindow) qCDebug(lcQpaWindow) << __FUNCTION__ << window() << "newParent=" << newParentWindow << newParent << "oldStyle=" << debugWinStyle(oldStyle); - auto updateWindowFlags = [&] { + auto updateWindowFlags = [&]{ // Top level window flags need to be set/cleared manually. DWORD newStyle = oldStyle; if (isTopLevel) { @@ -1588,7 +1613,8 @@ void QWindowsWindow::initialize() QWindowSystemInterface::handleGeometryChange(w, obtainedGeometry); } } - QWindowsWindow::setSavedDpi(GetDpiForWindow(handle())); + QWindowsWindow::setSavedDpi(QWindowsContext::user32dll.getDpiForWindow ? + QWindowsContext::user32dll.getDpiForWindow(handle()) : vxkex::GetDpiForWindow(handle())); } QSurfaceFormat QWindowsWindow::format() const @@ -2083,7 +2109,7 @@ void QWindowsWindow::handleDpiChanged(HWND hwnd, WPARAM wParam, LPARAM lParam) void QWindowsWindow::handleDpiChangedAfterParent(HWND hwnd) { - const UINT dpi = GetDpiForWindow(hwnd); + const UINT dpi = QWindowsContext::user32dll.getDpiForWindow ? QWindowsContext::user32dll.getDpiForWindow(hwnd) : vxkex::GetDpiForWindow(hwnd); const qreal scale = dpiRelativeScale(dpi); setSavedDpi(dpi); @@ -2177,6 +2203,7 @@ void QWindowsWindow::setGeometry(const QRect &rectIn) } if (m_windowState & Qt::WindowMinimized) m_data.geometry = rect; // Otherwise set by handleGeometryChange() triggered by event. + if (m_data.hwnd) { // A ResizeEvent with resulting geometry will be sent. If we cannot // achieve that size (for example, window title minimal constraint), diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiaaccessibility.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiaaccessibility.cpp index 638d684ce4f..1c89fd87ede 100644 --- a/src/plugins/platforms/windows/uiautomation/qwindowsuiaaccessibility.cpp +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiaaccessibility.cpp @@ -15,6 +15,8 @@ #include #include #include +#include "qwindowsuiawrapper_p.h" +#include "qwindowsuiawrapper.cpp" #include @@ -47,7 +49,7 @@ bool QWindowsUiaAccessibility::handleWmGetObject(HWND hwnd, WPARAM wParam, LPARA if (QWindow *window = QWindowsContext::instance()->findWindow(hwnd)) { if (QAccessibleInterface *accessible = window->accessibleRoot()) { auto provider = QWindowsUiaMainProvider::providerForAccessible(accessible); - *lResult = UiaReturnRawElementProvider(hwnd, wParam, lParam, provider.Get()); + *lResult = QWindowsUiaWrapper::instance()->returnRawElementProvider(hwnd, wParam, lParam, provider.Get()); return true; } } @@ -122,8 +124,12 @@ void QWindowsUiaAccessibility::notifyAccessibilityUpdate(QAccessibleEvent *event if (!isActive() || !accessible || !accessible->isValid()) return; + // Ensures QWindowsUiaWrapper is properly initialized. + if (!QWindowsUiaWrapper::instance()->ready()) + return; + // No need to do anything when nobody is listening. - if (!UiaClientsAreListening()) + if (!QWindowsUiaWrapper::instance()->clientsAreListening()) return; switch (event->type()) { diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp index f01c594b6cd..02e853da78b 100644 --- a/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp @@ -21,6 +21,7 @@ #include "qwindowscontext.h" #include "qwindowsuiautils.h" #include "qwindowsuiaprovidercache.h" +#include "qwindowsuiawrapper_p.h" #include #include @@ -75,7 +76,7 @@ void QWindowsUiaMainProvider::notifyFocusChange(QAccessibleEvent *event) accessible = child; } if (auto provider = providerForAccessible(accessible)) - UiaRaiseAutomationEvent(provider.Get(), UIA_AutomationFocusChangedEventId); + QWindowsUiaWrapper::instance()->raiseAutomationEvent(provider.Get(), UIA_AutomationFocusChangedEventId); } } @@ -92,7 +93,7 @@ void QWindowsUiaMainProvider::notifyStateChange(QAccessibleStateChangeEvent *eve QComVariant oldVal; QComVariant newVal{toggleState}; - UiaRaiseAutomationPropertyChangedEvent( + QWindowsUiaWrapper::instance()->raiseAutomationPropertyChangedEvent( provider.Get(), UIA_ToggleToggleStatePropertyId, oldVal.get(), newVal.get()); } } @@ -102,15 +103,15 @@ void QWindowsUiaMainProvider::notifyStateChange(QAccessibleStateChangeEvent *eve // Notifies window opened/closed. if (auto provider = providerForAccessible(accessible)) { if (accessible->state().active) { - UiaRaiseAutomationEvent(provider.Get(), UIA_Window_WindowOpenedEventId); + QWindowsUiaWrapper::instance()->raiseAutomationEvent(provider.Get(), UIA_Window_WindowOpenedEventId); if (QAccessibleInterface *focused = accessible->focusChild()) { if (auto focusedProvider = providerForAccessible(focused)) { - UiaRaiseAutomationEvent(focusedProvider.Get(), + QWindowsUiaWrapper::instance()->raiseAutomationEvent(focusedProvider.Get(), UIA_AutomationFocusChangedEventId); } } } else { - UiaRaiseAutomationEvent(provider.Get(), UIA_Window_WindowClosedEventId); + QWindowsUiaWrapper::instance()->raiseAutomationEvent(provider.Get(), UIA_Window_WindowClosedEventId); } } } @@ -142,7 +143,7 @@ void QWindowsUiaMainProvider::notifyValueChange(QAccessibleValueChangeEvent *eve // Notifies changes in string values. const QComVariant oldVal; const QComVariant newVal{ event->value().toString() }; - UiaRaiseAutomationPropertyChangedEvent(provider.Get(), UIA_ValueValuePropertyId, + QWindowsUiaWrapper::instance()->raiseAutomationPropertyChangedEvent(provider.Get(), UIA_ValueValuePropertyId, oldVal.get(), newVal.get()); } } else if (QAccessibleValueInterface *valueInterface = accessible->valueInterface()) { @@ -150,7 +151,7 @@ void QWindowsUiaMainProvider::notifyValueChange(QAccessibleValueChangeEvent *eve // Notifies changes in values of controls supporting the value interface. const QComVariant oldVal; const QComVariant newVal{ valueInterface->currentValue().toDouble() }; - UiaRaiseAutomationPropertyChangedEvent( + QWindowsUiaWrapper::instance()->raiseAutomationPropertyChangedEvent( provider.Get(), UIA_RangeValueValuePropertyId, oldVal.get(), newVal.get()); } } @@ -166,7 +167,7 @@ void QWindowsUiaMainProvider::notifyNameChange(QAccessibleEvent *event) if (auto provider = providerForAccessible(accessible)) { QComVariant oldVal; QComVariant newVal{ accessible->text(QAccessible::Name) }; - UiaRaiseAutomationPropertyChangedEvent(provider.Get(), UIA_NamePropertyId, + QWindowsUiaWrapper::instance()->raiseAutomationPropertyChangedEvent(provider.Get(), UIA_NamePropertyId, oldVal.get(), newVal.get()); } } @@ -177,7 +178,7 @@ void QWindowsUiaMainProvider::notifySelectionChange(QAccessibleEvent *event) { if (QAccessibleInterface *accessible = event->accessibleInterface()) { if (auto provider = providerForAccessible(accessible)) - UiaRaiseAutomationEvent(provider.Get(), UIA_SelectionItem_ElementSelectedEventId); + QWindowsUiaWrapper::instance()->raiseAutomationEvent(provider.Get(), UIA_SelectionItem_ElementSelectedEventId); } } @@ -188,14 +189,14 @@ void QWindowsUiaMainProvider::notifyTextChange(QAccessibleEvent *event) if (accessible->textInterface()) { if (auto provider = providerForAccessible(accessible)) { if (event->type() == QAccessible::TextSelectionChanged) { - UiaRaiseAutomationEvent(provider.Get(), UIA_Text_TextSelectionChangedEventId); + QWindowsUiaWrapper::instance()->raiseAutomationEvent(provider.Get(), UIA_Text_TextSelectionChangedEventId); } else if (event->type() == QAccessible::TextCaretMoved) { if (!accessible->state().readOnly) { - UiaRaiseAutomationEvent(provider.Get(), + QWindowsUiaWrapper::instance()->raiseAutomationEvent(provider.Get(), UIA_Text_TextSelectionChangedEventId); } } else { - UiaRaiseAutomationEvent(provider.Get(), UIA_Text_TextChangedEventId); + QWindowsUiaWrapper::instance()->raiseAutomationEvent(provider.Get(), UIA_Text_TextChangedEventId); } } } @@ -212,7 +213,7 @@ void QWindowsUiaMainProvider::raiseNotification(QAccessibleAnnouncementEvent *ev ? NotificationProcessing_ImportantAll : NotificationProcessing_All; QBStr activityId{ QString::fromLatin1("") }; - UiaRaiseNotificationEvent(provider.Get(), NotificationKind_Other, processing, message.bstr(), + QWindowsUiaWrapper::instance()->raiseNotificationEvent(provider.Get(), NotificationKind_Other, processing, message.bstr(), activityId.bstr()); } @@ -615,7 +616,7 @@ HRESULT QWindowsUiaMainProvider::get_HostRawElementProvider(IRawElementProviderS // Returns a host provider only for controls associated with a native window handle. Others should return NULL. if (QAccessibleInterface *accessible = accessibleInterface()) { if (HWND hwnd = hwndForAccessible(accessible)) { - return UiaHostProviderFromHwnd(hwnd, pRetVal); + return QWindowsUiaWrapper::instance()->hostProviderFromHwnd(hwnd, pRetVal); } } return S_OK; diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiawrapper.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiawrapper.cpp new file mode 100644 index 00000000000..caeb8e1da48 --- /dev/null +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiawrapper.cpp @@ -0,0 +1,89 @@ +// Copyright (C) 2017 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 + +#include "qwindowsuiawrapper_p.h" +#include + +QT_BEGIN_NAMESPACE + +// private constructor +QWindowsUiaWrapper::QWindowsUiaWrapper() +{ + QSystemLibrary uiaLib(QStringLiteral("UIAutomationCore")); + if (uiaLib.load()) { + m_pUiaReturnRawElementProvider = reinterpret_cast(uiaLib.resolve("UiaReturnRawElementProvider")); + m_pUiaHostProviderFromHwnd = reinterpret_cast(uiaLib.resolve("UiaHostProviderFromHwnd")); + m_pUiaRaiseAutomationPropertyChangedEvent = reinterpret_cast(uiaLib.resolve("UiaRaiseAutomationPropertyChangedEvent")); + m_pUiaRaiseAutomationEvent = reinterpret_cast(uiaLib.resolve("UiaRaiseAutomationEvent")); + m_pUiaRaiseNotificationEvent = reinterpret_cast(uiaLib.resolve("UiaRaiseNotificationEvent")); + m_pUiaClientsAreListening = reinterpret_cast(uiaLib.resolve("UiaClientsAreListening")); + } +} + +QWindowsUiaWrapper::~QWindowsUiaWrapper() +{ +} + +// shared instance +QWindowsUiaWrapper *QWindowsUiaWrapper::instance() +{ + static QWindowsUiaWrapper wrapper; + return &wrapper; +} + +// True if all symbols resolved. +BOOL QWindowsUiaWrapper::ready() +{ + return m_pUiaReturnRawElementProvider + && m_pUiaHostProviderFromHwnd + && m_pUiaRaiseAutomationPropertyChangedEvent + && m_pUiaRaiseAutomationEvent + && m_pUiaClientsAreListening; +} + +BOOL QWindowsUiaWrapper::clientsAreListening() +{ + if (!m_pUiaClientsAreListening) + return FALSE; + return m_pUiaClientsAreListening(); +} + +LRESULT QWindowsUiaWrapper::returnRawElementProvider(HWND hwnd, WPARAM wParam, LPARAM lParam, IRawElementProviderSimple *el) +{ + if (!m_pUiaReturnRawElementProvider) + return static_cast(NULL); + return m_pUiaReturnRawElementProvider(hwnd, wParam, lParam, el); +} + +HRESULT QWindowsUiaWrapper::hostProviderFromHwnd(HWND hwnd, IRawElementProviderSimple **ppProvider) +{ + if (!m_pUiaHostProviderFromHwnd) + return UIA_E_NOTSUPPORTED; + return m_pUiaHostProviderFromHwnd(hwnd, ppProvider); +} + +HRESULT QWindowsUiaWrapper::raiseAutomationPropertyChangedEvent(IRawElementProviderSimple *pProvider, PROPERTYID id, VARIANT oldValue, VARIANT newValue) +{ + if (!m_pUiaRaiseAutomationPropertyChangedEvent) + return UIA_E_NOTSUPPORTED; + return m_pUiaRaiseAutomationPropertyChangedEvent(pProvider, id, oldValue, newValue); +} + +HRESULT QWindowsUiaWrapper::raiseAutomationEvent(IRawElementProviderSimple *pProvider, EVENTID id) +{ + if (!m_pUiaRaiseAutomationEvent) + return UIA_E_NOTSUPPORTED; + return m_pUiaRaiseAutomationEvent(pProvider, id); +} + +HRESULT QWindowsUiaWrapper::raiseNotificationEvent(IRawElementProviderSimple *pProvider, NotificationKind notificationKind, NotificationProcessing notificationProcessing, BSTR displayString, BSTR activityId) +{ + if (!m_pUiaRaiseNotificationEvent) + return UIA_E_NOTSUPPORTED; + return m_pUiaRaiseNotificationEvent(pProvider, notificationKind, notificationProcessing, displayString, activityId); +} + +QT_END_NAMESPACE + diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiawrapper_p.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiawrapper_p.h new file mode 100644 index 00000000000..e005318114c --- /dev/null +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiawrapper_p.h @@ -0,0 +1,57 @@ +// Copyright (C) 2017 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 + +#ifndef QWINDOWSUIAWRAPPER_H +#define QWINDOWSUIAWRAPPER_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +QT_REQUIRE_CONFIG(accessibility); + +QT_BEGIN_NAMESPACE + +class QWindowsUiaWrapper +{ + QWindowsUiaWrapper(); + virtual ~QWindowsUiaWrapper(); +public: + static QWindowsUiaWrapper *instance(); + BOOL ready(); + BOOL clientsAreListening(); + LRESULT returnRawElementProvider(HWND hwnd, WPARAM wParam, LPARAM lParam, IRawElementProviderSimple *el); + HRESULT hostProviderFromHwnd(HWND hwnd, IRawElementProviderSimple **ppProvider); + HRESULT raiseAutomationPropertyChangedEvent(IRawElementProviderSimple *pProvider, PROPERTYID id, VARIANT oldValue, VARIANT newValue); + HRESULT raiseAutomationEvent(IRawElementProviderSimple *pProvider, EVENTID id); + HRESULT raiseNotificationEvent(IRawElementProviderSimple *pProvider, NotificationKind notificationKind, NotificationProcessing notificationProcessing, BSTR displayString, BSTR activityId); + +private: + typedef LRESULT (WINAPI *PtrUiaReturnRawElementProvider)(HWND, WPARAM, LPARAM, IRawElementProviderSimple *); + typedef HRESULT (WINAPI *PtrUiaHostProviderFromHwnd)(HWND, IRawElementProviderSimple **); + typedef HRESULT (WINAPI *PtrUiaRaiseAutomationPropertyChangedEvent)(IRawElementProviderSimple *, PROPERTYID, VARIANT, VARIANT); + typedef HRESULT (WINAPI *PtrUiaRaiseAutomationEvent)(IRawElementProviderSimple *, EVENTID); + typedef HRESULT (WINAPI *PtrUiaRaiseNotificationEvent)(IRawElementProviderSimple *, NotificationKind, NotificationProcessing, BSTR, BSTR); + + typedef BOOL (WINAPI *PtrUiaClientsAreListening)(); + PtrUiaReturnRawElementProvider m_pUiaReturnRawElementProvider = nullptr; + PtrUiaHostProviderFromHwnd m_pUiaHostProviderFromHwnd = nullptr; + PtrUiaRaiseAutomationPropertyChangedEvent m_pUiaRaiseAutomationPropertyChangedEvent = nullptr; + PtrUiaRaiseAutomationEvent m_pUiaRaiseAutomationEvent = nullptr; + PtrUiaRaiseNotificationEvent m_pUiaRaiseNotificationEvent = nullptr; + PtrUiaClientsAreListening m_pUiaClientsAreListening = nullptr; +}; + +QT_END_NAMESPACE + +#endif //QWINDOWSUIAWRAPPER_H + diff --git a/src/plugins/platforms/windows/vxkex.h b/src/plugins/platforms/windows/vxkex.h new file mode 100644 index 00000000000..6bbf2209f43 --- /dev/null +++ b/src/plugins/platforms/windows/vxkex.h @@ -0,0 +1,426 @@ +#pragma once + +#include +#include +#include +#include + +#define MDT_MAXIMUM_DPI 3 + +namespace vxkex { + +static INT GetSystemMetricsForDpi( + IN INT Index, + IN UINT Dpi) +{ + INT Value; + + Value = GetSystemMetrics(Index); + + switch (Index) { + case SM_CXVSCROLL: + case SM_CYHSCROLL: + case SM_CYCAPTION: + case SM_CYVTHUMB: + case SM_CXHTHUMB: + case SM_CXICON: + case SM_CYICON: + case SM_CXCURSOR: + case SM_CYCURSOR: + case SM_CYMENU: + case SM_CYVSCROLL: + case SM_CXHSCROLL: + case SM_CXMIN: + case SM_CXMINTRACK: + case SM_CYMIN: + case SM_CYMINTRACK: + case SM_CXSIZE: + case SM_CXFRAME: + case SM_CYFRAME: + case SM_CXICONSPACING: + case SM_CYICONSPACING: + case SM_CXSMICON: + case SM_CYSMICON: + case SM_CYSMCAPTION: + case SM_CXSMSIZE: + case SM_CYSMSIZE: + case SM_CXMENUSIZE: + case SM_CYMENUSIZE: + case SM_CXMENUCHECK: + case SM_CYMENUCHECK: + // These are pixel values that have to be scaled according to DPI. + Value *= Dpi; + Value /= USER_DEFAULT_SCREEN_DPI; + break; + } + + return Value; +} + +static BOOL SystemParametersInfoForDpi( + IN UINT Action, + IN UINT Parameter, + IN OUT PVOID Data, + IN UINT WinIni, + IN UINT Dpi) +{ + switch (Action) { + case SPI_GETICONTITLELOGFONT: + return SystemParametersInfo(Action, Parameter, Data, 0); + case SPI_GETICONMETRICS: + { + BOOL Success; + PICONMETRICS IconMetrics; + + Success = SystemParametersInfo(Action, Parameter, Data, 0); + + if (Success) { + IconMetrics = (PICONMETRICS) Data; + + IconMetrics->iHorzSpacing *= Dpi; + IconMetrics->iVertSpacing *= Dpi; + IconMetrics->iHorzSpacing /= USER_DEFAULT_SCREEN_DPI; + IconMetrics->iVertSpacing /= USER_DEFAULT_SCREEN_DPI; + } + + return Success; + } + case SPI_GETNONCLIENTMETRICS: + { + BOOL Success; + PNONCLIENTMETRICS NonClientMetrics; + + Success = SystemParametersInfo(Action, Parameter, Data, 0); + + if (Success) { + NonClientMetrics = (PNONCLIENTMETRICS) Data; + + NonClientMetrics->iBorderWidth *= Dpi; + NonClientMetrics->iScrollWidth *= Dpi; + NonClientMetrics->iScrollHeight *= Dpi; + NonClientMetrics->iCaptionWidth *= Dpi; + NonClientMetrics->iCaptionHeight *= Dpi; + NonClientMetrics->iSmCaptionWidth *= Dpi; + NonClientMetrics->iSmCaptionHeight *= Dpi; + NonClientMetrics->iMenuWidth *= Dpi; + NonClientMetrics->iMenuHeight *= Dpi; + NonClientMetrics->iPaddedBorderWidth *= Dpi; + + NonClientMetrics->iBorderWidth /= USER_DEFAULT_SCREEN_DPI; + NonClientMetrics->iScrollWidth /= USER_DEFAULT_SCREEN_DPI; + NonClientMetrics->iScrollHeight /= USER_DEFAULT_SCREEN_DPI; + NonClientMetrics->iCaptionWidth /= USER_DEFAULT_SCREEN_DPI; + NonClientMetrics->iCaptionHeight /= USER_DEFAULT_SCREEN_DPI; + NonClientMetrics->iSmCaptionWidth /= USER_DEFAULT_SCREEN_DPI; + NonClientMetrics->iSmCaptionHeight /= USER_DEFAULT_SCREEN_DPI; + NonClientMetrics->iMenuWidth /= USER_DEFAULT_SCREEN_DPI; + NonClientMetrics->iMenuHeight /= USER_DEFAULT_SCREEN_DPI; + NonClientMetrics->iPaddedBorderWidth /= USER_DEFAULT_SCREEN_DPI; + } + + return Success; + } + default: + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } +} + +static HRESULT GetScaleFactorForMonitor( + IN HMONITOR Monitor, + OUT DEVICE_SCALE_FACTOR *ScaleFactor) +{ + HDC DeviceContext; + ULONG LogPixelsX; + + DeviceContext = GetDC(NULL); + if (!DeviceContext) { + *ScaleFactor = SCALE_100_PERCENT; + return S_OK; + } + + LogPixelsX = GetDeviceCaps(DeviceContext, LOGPIXELSX); + ReleaseDC(NULL, DeviceContext); + + *ScaleFactor = (DEVICE_SCALE_FACTOR) (9600 / LogPixelsX); + return S_OK; +} + +static HRESULT GetDpiForMonitor( + IN HMONITOR Monitor, + IN MONITOR_DPI_TYPE DpiType, + OUT UINT * DpiX, + OUT UINT * DpiY) +{ + HDC DeviceContext; + + if (DpiType >= MDT_MAXIMUM_DPI) { + return E_INVALIDARG; + } + + if (!DpiX || !DpiY) { + return E_INVALIDARG; + } + + if (!IsProcessDPIAware()) { + *DpiX = USER_DEFAULT_SCREEN_DPI; + *DpiY = USER_DEFAULT_SCREEN_DPI; + return S_OK; + } + + DeviceContext = GetDC(NULL); + if (!DeviceContext) { + *DpiX = USER_DEFAULT_SCREEN_DPI; + *DpiY = USER_DEFAULT_SCREEN_DPI; + return S_OK; + } + + *DpiX = GetDeviceCaps(DeviceContext, LOGPIXELSX); + *DpiY = GetDeviceCaps(DeviceContext, LOGPIXELSY); + + if (DpiType == MDT_EFFECTIVE_DPI) { + DEVICE_SCALE_FACTOR ScaleFactor; + + // We have to multiply the DPI values by the scaling factor. + vxkex::GetScaleFactorForMonitor(Monitor, &ScaleFactor); + + *DpiX *= ScaleFactor; + *DpiY *= ScaleFactor; + *DpiX /= 100; + *DpiY /= 100; + } + + ReleaseDC(NULL, DeviceContext); + return S_OK; +} + +static UINT GetDpiForSystem( + VOID) +{ + HDC DeviceContext; + ULONG LogPixelsX; + + if (!IsProcessDPIAware()) { + return 96; + } + + DeviceContext = GetDC(NULL); + if (!DeviceContext) { + return 96; + } + + LogPixelsX = GetDeviceCaps(DeviceContext, LOGPIXELSX); + ReleaseDC(NULL, DeviceContext); + + return LogPixelsX; +} + +static UINT GetDpiForWindow( + IN HWND Window) +{ + if (!IsWindow(Window)) { + return 0; + } + + return vxkex::GetDpiForSystem(); +} + +static BOOL AdjustWindowRectExForDpi( + IN OUT LPRECT Rect, + IN ULONG WindowStyle, + IN BOOL HasMenu, + IN ULONG WindowExStyle, + IN ULONG Dpi) +{ + // I'm not sure how to implement this function properly. + // If it turns out to be important, I'll have to do some testing + // on a Win10 VM. + + return AdjustWindowRectEx( + Rect, + WindowStyle, + HasMenu, + WindowExStyle); +} + +static BOOL SetDisplayAutoRotationPreferences( + IN ORIENTATION_PREFERENCE Orientation) +{ + return TRUE; +} + +static BOOL GetDisplayAutoRotationPreferences( + OUT ORIENTATION_PREFERENCE * Orientation) +{ + *Orientation = ORIENTATION_PREFERENCE_NONE; + return TRUE; +} + +// scaling.c + +static BOOL SetProcessDpiAwarenessContext( + IN DPI_AWARENESS_CONTEXT DpiContext) +{ + if ((ULONG_PTR)DpiContext == (ULONG_PTR)DPI_AWARENESS_CONTEXT_UNAWARE) { + //NOTHING; + } else if ((ULONG_PTR)DpiContext == (ULONG_PTR)DPI_AWARENESS_CONTEXT_SYSTEM_AWARE || + (ULONG_PTR)DpiContext == (ULONG_PTR)DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE || + (ULONG_PTR)DpiContext == (ULONG_PTR)DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2) { + SetProcessDPIAware(); + } else { + return FALSE; + } + + return TRUE; +} + +static BOOL AreDpiAwarenessContextsEqual( + IN DPI_AWARENESS_CONTEXT Value1, + IN DPI_AWARENESS_CONTEXT Value2) +{ + return (Value1 == Value2); +} + +static BOOL IsValidDpiAwarenessContext( + IN DPI_AWARENESS_CONTEXT Value) +{ + if ((ULONG_PTR)Value == (ULONG_PTR)DPI_AWARENESS_CONTEXT_UNAWARE || + (ULONG_PTR)Value == (ULONG_PTR)DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED || + (ULONG_PTR)Value == (ULONG_PTR)DPI_AWARENESS_CONTEXT_SYSTEM_AWARE || + (ULONG_PTR)Value == (ULONG_PTR)DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE || + (ULONG_PTR)Value == (ULONG_PTR)DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2) { + return TRUE; + } else { + return FALSE; + } +} + +static BOOL EnableNonClientDpiScaling( + IN HWND Window) +{ + return TRUE; +} + +static DPI_AWARENESS_CONTEXT GetThreadDpiAwarenessContext( + VOID) +{ + if (IsProcessDPIAware()) { + return DPI_AWARENESS_CONTEXT_SYSTEM_AWARE; + } else { + return DPI_AWARENESS_CONTEXT_UNAWARE; + } +} + +static DPI_AWARENESS_CONTEXT GetWindowDpiAwarenessContext( + IN HWND Window) +{ + ULONG WindowThreadId; + ULONG WindowProcessId; + + WindowThreadId = GetWindowThreadProcessId(Window, &WindowProcessId); + if (!WindowThreadId) { + return 0; + } + + // looks like there's a bug in vxkex, here should be == instead of = + // and if is always true + // anyway I don't want to deal with Windows kernel mode structures here + + if (1) { //if (WindowProcessId = (ULONG) NtCurrentTeb()->ClientId.UniqueProcess) { + return vxkex::GetThreadDpiAwarenessContext(); + } + + return DPI_AWARENESS_CONTEXT_UNAWARE; +} + +// pointer.c + +static BOOL GetPointerType( + IN UINT32 PointerId, + OUT POINTER_INPUT_TYPE *PointerType) +{ + *PointerType = PT_MOUSE; + return TRUE; +} + +static BOOL GetPointerFrameTouchInfo( + IN UINT32 PointerId, + IN OUT UINT32 *PointerCount, + OUT LPVOID TouchInfo) +{ + return FALSE; +} + +static BOOL GetPointerFrameTouchInfoHistory( + IN UINT32 PointerId, + IN OUT UINT32 *EntriesCount, + IN OUT UINT32 *PointerCount, + OUT LPVOID TouchInfo) +{ + return FALSE; +} + +static BOOL GetPointerPenInfo( + IN UINT32 PointerId, + OUT LPVOID PenInfo) +{ + return FALSE; +} + +static BOOL GetPointerPenInfoHistory( + IN UINT32 PointerId, + IN OUT UINT32 *EntriesCount, + OUT LPVOID PenInfo) +{ + return FALSE; +} + +static BOOL SkipPointerFrameMessages( + IN UINT32 PointerId) +{ + return TRUE; +} + +static BOOL GetPointerDeviceRects( + IN HANDLE Device, + OUT LPRECT PointerDeviceRect, + OUT LPRECT DisplayRect) +{ + PointerDeviceRect->top = 0; + PointerDeviceRect->left = 0; + PointerDeviceRect->bottom = GetSystemMetrics(SM_CYVIRTUALSCREEN); + PointerDeviceRect->right = GetSystemMetrics(SM_CXVIRTUALSCREEN); + + DisplayRect->top = 0; + DisplayRect->left = 0; + DisplayRect->bottom = GetSystemMetrics(SM_CYVIRTUALSCREEN); + DisplayRect->right = GetSystemMetrics(SM_CXVIRTUALSCREEN); + + return TRUE; +} + +static BOOL GetPointerInfo( + IN DWORD PointerId, + OUT POINTER_INFO *PointerInfo) +{ + PointerInfo->pointerType = PT_MOUSE; + PointerInfo->pointerId = PointerId; + PointerInfo->frameId = 0; + PointerInfo->pointerFlags = POINTER_FLAG_NONE; + PointerInfo->sourceDevice = NULL; + PointerInfo->hwndTarget = NULL; + GetCursorPos(&PointerInfo->ptPixelLocation); + GetCursorPos(&PointerInfo->ptHimetricLocation); + GetCursorPos(&PointerInfo->ptPixelLocationRaw); + GetCursorPos(&PointerInfo->ptHimetricLocationRaw); + PointerInfo->dwTime = 0; + PointerInfo->historyCount = 1; + PointerInfo->InputData = 0; + PointerInfo->dwKeyStates = 0; + PointerInfo->PerformanceCount = 0; + PointerInfo->ButtonChangeType = POINTER_CHANGE_NONE; + + return TRUE; +} + +} // namespace vxkex diff --git a/src/widgets/styles/qwindowsstyle.cpp b/src/widgets/styles/qwindowsstyle.cpp index a8407add019..a8097330210 100644 --- a/src/widgets/styles/qwindowsstyle.cpp +++ b/src/widgets/styles/qwindowsstyle.cpp @@ -59,6 +59,10 @@ #include +#if defined(Q_OS_WIN) +#include "../../plugins/platforms/windows/vxkex.h" +#endif + QT_BEGIN_NAMESPACE #if defined(Q_OS_WIN) @@ -254,6 +258,11 @@ void QWindowsStyle::polish(QPalette &pal) QCommonStyle::polish(pal); } +#if defined(Q_OS_WIN) +typedef BOOL (WINAPI *GetSystemMetricsForDpiFunc)(int, UINT); +typedef BOOL (WINAPI *SystemParametersInfoForDpiFunc)(UINT, UINT, PVOID, UINT, UINT); +#endif + int QWindowsStylePrivate::pixelMetricFromSystemDp(QStyle::PixelMetric pm, const QStyleOption *, const QWidget *widget) { #if defined(Q_OS_WIN) @@ -261,29 +270,43 @@ int QWindowsStylePrivate::pixelMetricFromSystemDp(QStyle::PixelMetric pm, const // hardcode DPI to 1x 96 DPI. const int dpi = 96; + static GetSystemMetricsForDpiFunc myGetSystemMetricsForDpi = + (GetSystemMetricsForDpiFunc)::GetProcAddress(::GetModuleHandle(L"User32"), "GetSystemMetricsForDpi"); + + static SystemParametersInfoForDpiFunc mySystemParametersInfoForDpi = + (SystemParametersInfoForDpiFunc)::GetProcAddress(::GetModuleHandle(L"User32"), "SystemParametersInfoForDpi"); + switch (pm) { case QStyle::PM_DockWidgetFrameWidth: - return GetSystemMetricsForDpi(SM_CXFRAME, dpi); + return myGetSystemMetricsForDpi ? myGetSystemMetricsForDpi(SM_CXFRAME, dpi) : vxkex::GetSystemMetricsForDpi(SM_CXFRAME, dpi); case QStyle::PM_TitleBarHeight: { - const int resizeBorderThickness = - GetSystemMetricsForDpi(SM_CXSIZEFRAME, dpi) + GetSystemMetricsForDpi(SM_CXPADDEDBORDER, dpi); + const int resizeBorderThickness = myGetSystemMetricsForDpi ? + (myGetSystemMetricsForDpi(SM_CXSIZEFRAME, dpi) + myGetSystemMetricsForDpi(SM_CXPADDEDBORDER, dpi)) : + (vxkex::GetSystemMetricsForDpi(SM_CXSIZEFRAME, dpi) + vxkex::GetSystemMetricsForDpi(SM_CXPADDEDBORDER, dpi)) ; if (widget && (widget->windowType() == Qt::Tool)) - return GetSystemMetricsForDpi(SM_CYSMCAPTION, dpi) + resizeBorderThickness; - return GetSystemMetricsForDpi(SM_CYCAPTION, dpi) + resizeBorderThickness; + return myGetSystemMetricsForDpi ? + (myGetSystemMetricsForDpi(SM_CYSMCAPTION, dpi) + resizeBorderThickness) : + (vxkex::GetSystemMetricsForDpi(SM_CYSMCAPTION, dpi) + resizeBorderThickness); + return myGetSystemMetricsForDpi ? + (myGetSystemMetricsForDpi(SM_CYCAPTION, dpi) + resizeBorderThickness) : + (vxkex::GetSystemMetricsForDpi(SM_CYCAPTION, dpi) + resizeBorderThickness); } case QStyle::PM_ScrollBarExtent: { NONCLIENTMETRICS ncm; ncm.cbSize = sizeof(NONCLIENTMETRICS); - if (SystemParametersInfoForDpi(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &ncm, 0, dpi)) + BOOL bResult = mySystemParametersInfoForDpi + ? mySystemParametersInfoForDpi(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &ncm, 0, dpi) + : vxkex::SystemParametersInfoForDpi(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &ncm, 0, dpi); + if (bResult) return qMax(ncm.iScrollHeight, ncm.iScrollWidth); } break; case QStyle::PM_MdiSubWindowFrameWidth: - return GetSystemMetricsForDpi(SM_CYFRAME, dpi); + return myGetSystemMetricsForDpi ? myGetSystemMetricsForDpi(SM_CYFRAME, dpi) : vxkex::GetSystemMetricsForDpi(SM_CYFRAME, dpi); default: break;