update to Qt 6.7.3

This commit is contained in:
kleuter 2024-06-29 14:33:57 +02:00
parent d8e4680eb6
commit 36dc9b47f0
19 changed files with 4278 additions and 908 deletions

View File

@ -112,8 +112,10 @@ static GUID writableSpecialFolderId(QStandardPaths::StandardLocation type)
FOLDERID_LocalAppData, // AppConfigLocation ("Local" path) FOLDERID_LocalAppData, // AppConfigLocation ("Local" path)
FOLDERID_Public, // PublicShareLocation FOLDERID_Public, // PublicShareLocation
FOLDERID_Templates, // TemplatesLocation FOLDERID_Templates, // TemplatesLocation
GUID(), // StateLocation
GUID(), // GenericStateLocation
}; };
static_assert(sizeof(folderIds) / sizeof(folderIds[0]) == size_t(QStandardPaths::TemplatesLocation + 1)); static_assert(sizeof(folderIds) / sizeof(folderIds[0]) == size_t(QStandardPaths::GenericStateLocation + 1));
// folders for low integrity processes // folders for low integrity processes
static const GUID folderIds_li[] = { static const GUID folderIds_li[] = {
@ -137,6 +139,8 @@ static GUID writableSpecialFolderId(QStandardPaths::StandardLocation type)
FOLDERID_LocalAppDataLow,// AppConfigLocation ("Local" path) FOLDERID_LocalAppDataLow,// AppConfigLocation ("Local" path)
FOLDERID_Public, // PublicShareLocation FOLDERID_Public, // PublicShareLocation
FOLDERID_Templates, // TemplatesLocation FOLDERID_Templates, // TemplatesLocation
GUID(), // StateLocation
GUID(), // GenericStateLocation
}; };
static_assert(sizeof(folderIds_li) == sizeof(folderIds)); static_assert(sizeof(folderIds_li) == sizeof(folderIds));
@ -191,6 +195,23 @@ QString QStandardPaths::writableLocation(StandardLocation type)
result = QDir::tempPath(); result = QDir::tempPath();
break; break;
case StateLocation:
result = sHGetKnownFolderPath(writableSpecialFolderId(AppLocalDataLocation));
if (!result.isEmpty()) {
appendTestMode(result);
appendOrganizationAndApp(result);
result += "/State"_L1;
}
break;
case GenericStateLocation:
result = sHGetKnownFolderPath(writableSpecialFolderId(GenericDataLocation));
if (!result.isEmpty()) {
appendTestMode(result);
result += "/State"_L1;
}
break;
default: default:
result = sHGetKnownFolderPath(writableSpecialFolderId(type)); result = sHGetKnownFolderPath(writableSpecialFolderId(type));
if (!result.isEmpty() && isConfigLocation(type)) { if (!result.isEmpty() && isConfigLocation(type)) {

View File

@ -7,7 +7,6 @@
#include "qcoreapplication.h" #include "qcoreapplication.h"
#include <private/qsystemlibrary_p.h> #include <private/qsystemlibrary_p.h>
#include "qoperatingsystemversion.h" #include "qoperatingsystemversion.h"
#include "qpair.h"
#include "qset.h" #include "qset.h"
#include "qsocketnotifier.h" #include "qsocketnotifier.h"
#include "qvarlengtharray.h" #include "qvarlengtharray.h"
@ -136,7 +135,7 @@ LRESULT QT_WIN_CALLBACK qt_internal_proc(HWND hwnd, UINT message, WPARAM wp, LPA
QSNDict *sn_vec[4] = { &d->sn_read, &d->sn_write, &d->sn_except, &d->sn_read }; QSNDict *sn_vec[4] = { &d->sn_read, &d->sn_write, &d->sn_except, &d->sn_read };
QSNDict *dict = sn_vec[type]; QSNDict *dict = sn_vec[type];
QSockNot *sn = dict ? dict->value(wp) : 0; QSockNot *sn = dict ? dict->value(qintptr(wp)) : 0;
if (sn == nullptr) { if (sn == nullptr) {
d->postActivateSocketNotifiers(); d->postActivateSocketNotifiers();
} else { } else {
@ -414,7 +413,7 @@ void QEventDispatcherWin32Private::sendTimerEvent(int timerId)
} }
} }
void QEventDispatcherWin32Private::doWsaAsyncSelect(int socket, long event) void QEventDispatcherWin32Private::doWsaAsyncSelect(qintptr socket, long event)
{ {
Q_ASSERT(internalHwnd); Q_ASSERT(internalHwnd);
// BoundsChecker may emit a warning for WSAAsyncSelect when event == 0 // BoundsChecker may emit a warning for WSAAsyncSelect when event == 0
@ -563,7 +562,7 @@ bool QEventDispatcherWin32::processEvents(QEventLoop::ProcessEventsFlags flags)
void QEventDispatcherWin32::registerSocketNotifier(QSocketNotifier *notifier) void QEventDispatcherWin32::registerSocketNotifier(QSocketNotifier *notifier)
{ {
Q_ASSERT(notifier); Q_ASSERT(notifier);
int sockfd = notifier->socket(); qintptr sockfd = notifier->socket();
int type = notifier->type(); int type = notifier->type();
#ifndef QT_NO_DEBUG #ifndef QT_NO_DEBUG
if (sockfd < 0) { if (sockfd < 0) {
@ -587,7 +586,7 @@ void QEventDispatcherWin32::registerSocketNotifier(QSocketNotifier *notifier)
const char *t[] = { "Read", "Write", "Exception" }; const char *t[] = { "Read", "Write", "Exception" };
/* Variable "socket" below is a function pointer. */ /* Variable "socket" below is a function pointer. */
qWarning("QSocketNotifier: Multiple socket notifiers for " qWarning("QSocketNotifier: Multiple socket notifiers for "
"same socket %d and type %s", sockfd, t[type]); "same socket %" PRIdQINTPTR " and type %s", sockfd, t[type]);
} }
QSockNot *sn = new QSockNot; QSockNot *sn = new QSockNot;
@ -631,7 +630,7 @@ void QEventDispatcherWin32::unregisterSocketNotifier(QSocketNotifier *notifier)
{ {
Q_ASSERT(notifier); Q_ASSERT(notifier);
#ifndef QT_NO_DEBUG #ifndef QT_NO_DEBUG
int sockfd = notifier->socket(); qintptr sockfd = notifier->socket();
if (sockfd < 0) { if (sockfd < 0) {
qWarning("QEventDispatcherWin32::unregisterSocketNotifier: invalid socket identifier"); qWarning("QEventDispatcherWin32::unregisterSocketNotifier: invalid socket identifier");
return; return;
@ -648,7 +647,7 @@ void QEventDispatcherWin32::doUnregisterSocketNotifier(QSocketNotifier *notifier
{ {
Q_D(QEventDispatcherWin32); Q_D(QEventDispatcherWin32);
int type = notifier->type(); int type = notifier->type();
int sockfd = notifier->socket(); qintptr sockfd = notifier->socket();
Q_ASSERT(sockfd >= 0); Q_ASSERT(sockfd >= 0);
QSFDict::iterator it = d->active_fd.find(sockfd); QSFDict::iterator it = d->active_fd.find(sockfd);
@ -911,3 +910,5 @@ HWND QEventDispatcherWin32::internalHwnd()
} }
QT_END_NAMESPACE QT_END_NAMESPACE
#include "moc_qeventdispatcher_win_p.cpp"

View File

@ -51,21 +51,21 @@ bool qt_win_hasPackageIdentity()
{ {
#if defined(HAS_APPMODEL) #if defined(HAS_APPMODEL)
static const bool hasPackageIdentity = []() { static const bool hasPackageIdentity = []() {
UINT32 length = 0; UINT32 length = 0;
switch (const auto result = myGetCurrentPackageFullName(&length, nullptr)) { switch (const auto result = myGetCurrentPackageFullName(&length, nullptr)) {
case ERROR_INSUFFICIENT_BUFFER: case ERROR_INSUFFICIENT_BUFFER:
return true; return true;
case APPMODEL_ERROR_NO_PACKAGE: case APPMODEL_ERROR_NO_PACKAGE:
return false; return false;
default: default:
qWarning("Failed to resolve package identity (error code %ld)", result); qWarning("Failed to resolve package identity (error code %ld)", result);
return false; return false;
} }
}(); }();
return hasPackageIdentity; return hasPackageIdentity;
#else #else
return false; return false;
#endif #endif
} }

View File

@ -15,15 +15,15 @@
// We mean it. // We mean it.
// //
#include <qdeadlinetimer.h>
#include <private/qglobal_p.h> #include <private/qglobal_p.h>
#include <QtCore/qtsan_impl.h>
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
namespace QtDummyFutex { namespace QtDummyFutex {
constexpr inline bool futexAvailable() { return false; } constexpr inline bool futexAvailable() { return false; }
template <typename Atomic> template <typename Atomic>
inline bool futexWait(Atomic &, typename Atomic::Type, int = 0) inline bool futexWait(Atomic &, typename Atomic::Type, QDeadlineTimer = {})
{ Q_UNREACHABLE_RETURN(false); } { Q_UNREACHABLE_RETURN(false); }
template <typename Atomic> inline void futexWakeOne(Atomic &) template <typename Atomic> inline void futexWakeOne(Atomic &)
{ Q_UNREACHABLE(); } { Q_UNREACHABLE(); }
@ -33,82 +33,16 @@ namespace QtDummyFutex {
QT_END_NAMESPACE QT_END_NAMESPACE
#if defined(Q_OS_LINUX) && !defined(QT_LINUXBASE) #if defined(Q_OS_DARWIN)
# include "qfutex_mac_p.h"
#elif defined(Q_OS_FREEBSD)
# include "qfutex_freebsd_p.h"
#elif defined(Q_OS_LINUX) && !defined(QT_LINUXBASE)
// use Linux mutexes everywhere except for LSB builds // use Linux mutexes everywhere except for LSB builds
# include <sys/syscall.h> # include "qfutex_linux_p.h"
# include <errno.h> //#elif defined(Q_OS_WIN)
# include <limits.h> //# include "qfutex_win_p.h"
# include <unistd.h>
# include <asm/unistd.h>
# include <linux/futex.h>
# define QT_ALWAYS_USE_FUTEX
// if not defined in linux/futex.h
# define FUTEX_PRIVATE_FLAG 128 // added in v2.6.22
// RISC-V does not supply __NR_futex
# ifndef __NR_futex
# define __NR_futex __NR_futex_time64
# endif
QT_BEGIN_NAMESPACE
namespace QtLinuxFutex {
constexpr inline bool futexAvailable() { return true; }
inline int _q_futex(int *addr, int op, int val, quintptr val2 = 0,
int *addr2 = nullptr, int val3 = 0) noexcept
{
QtTsan::futexRelease(addr, addr2);
// we use __NR_futex because some libcs (like Android's bionic) don't
// provide SYS_futex etc.
int result = syscall(__NR_futex, addr, op | FUTEX_PRIVATE_FLAG, val, val2, addr2, val3);
QtTsan::futexAcquire(addr, addr2);
return result;
}
template <typename T> int *addr(T *ptr)
{
int *int_addr = reinterpret_cast<int *>(ptr);
#if Q_BYTE_ORDER == Q_BIG_ENDIAN
if (sizeof(T) > sizeof(int))
int_addr++; //We want a pointer to the least significant half
#endif
return int_addr;
}
template <typename Atomic>
inline void futexWait(Atomic &futex, typename Atomic::Type expectedValue)
{
_q_futex(addr(&futex), FUTEX_WAIT, qintptr(expectedValue));
}
template <typename Atomic>
inline bool futexWait(Atomic &futex, typename Atomic::Type expectedValue, qint64 nstimeout)
{
struct timespec ts;
ts.tv_sec = nstimeout / 1000 / 1000 / 1000;
ts.tv_nsec = nstimeout % (1000 * 1000 * 1000);
int r = _q_futex(addr(&futex), FUTEX_WAIT, qintptr(expectedValue), quintptr(&ts));
return r == 0 || errno != ETIMEDOUT;
}
template <typename Atomic> inline void futexWakeOne(Atomic &futex)
{
_q_futex(addr(&futex), FUTEX_WAKE, 1);
}
template <typename Atomic> inline void futexWakeAll(Atomic &futex)
{
_q_futex(addr(&futex), FUTEX_WAKE, INT_MAX);
}
template <typename Atomic> inline
void futexWakeOp(Atomic &futex1, int wake1, int wake2, Atomic &futex2, quint32 op)
{
_q_futex(addr(&futex1), FUTEX_WAKE_OP, wake1, wake2, addr(&futex2), op);
}
}
namespace QtFutex = QtLinuxFutex;
QT_END_NAMESPACE
#else #else
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
namespace QtFutex = QtDummyFutex; namespace QtFutex = QtDummyFutex;
QT_END_NAMESPACE QT_END_NAMESPACE

View File

@ -8,7 +8,6 @@
#include "qmutex.h" #include "qmutex.h"
#include <qdebug.h> #include <qdebug.h>
#include "qatomic.h" #include "qatomic.h"
#include "qelapsedtimer.h"
#include "qfutex_p.h" #include "qfutex_p.h"
#include "qthread.h" #include "qthread.h"
#include "qmutex_p.h" #include "qmutex_p.h"
@ -673,12 +672,11 @@ bool QBasicMutex::lockInternal(int timeout) QT_MUTEX_LOCK_NOEXCEPT
*/ */
bool QBasicMutex::lockInternal(QDeadlineTimer deadlineTimer) QT_MUTEX_LOCK_NOEXCEPT bool QBasicMutex::lockInternal(QDeadlineTimer deadlineTimer) QT_MUTEX_LOCK_NOEXCEPT
{ {
qint64 remainingTime = deadlineTimer.remainingTimeNSecs(); if (deadlineTimer.hasExpired())
if (remainingTime == 0)
return false; return false;
if (futexAvailable()) { if (futexAvailable()) {
if (Q_UNLIKELY(remainingTime < 0)) { // deadlineTimer.isForever() if (Q_UNLIKELY(deadlineTimer.isForever())) {
lockInternal(); lockInternal();
return true; return true;
} }
@ -689,8 +687,8 @@ bool QBasicMutex::lockInternal(QDeadlineTimer deadlineTimer) QT_MUTEX_LOCK_NOEXC
if (d_ptr.fetchAndStoreAcquire(dummyFutexValue()) == nullptr) if (d_ptr.fetchAndStoreAcquire(dummyFutexValue()) == nullptr)
return true; return true;
Q_FOREVER { for (;;) {
if (!futexWait(d_ptr, dummyFutexValue(), remainingTime)) if (!futexWait(d_ptr, dummyFutexValue(), deadlineTimer))
return false; return false;
// We got woken up, so must try to acquire the mutex. We must set // We got woken up, so must try to acquire the mutex. We must set
@ -699,9 +697,7 @@ bool QBasicMutex::lockInternal(QDeadlineTimer deadlineTimer) QT_MUTEX_LOCK_NOEXC
if (d_ptr.fetchAndStoreAcquire(dummyFutexValue()) == nullptr) if (d_ptr.fetchAndStoreAcquire(dummyFutexValue()) == nullptr)
return true; return true;
// calculate the remaining time if (deadlineTimer.hasExpired())
remainingTime = deadlineTimer.remainingTimeNSecs();
if (remainingTime <= 0)
return false; return false;
} }
} }
@ -713,7 +709,7 @@ bool QBasicMutex::lockInternal(QDeadlineTimer deadlineTimer) QT_MUTEX_LOCK_NOEXC
continue; continue;
if (copy == dummyLocked()) { if (copy == dummyLocked()) {
if (remainingTime == 0) if (deadlineTimer.hasExpired())
return false; return false;
// The mutex is locked but does not have a QMutexPrivate yet. // The mutex is locked but does not have a QMutexPrivate yet.
// we need to allocate a QMutexPrivate // we need to allocate a QMutexPrivate
@ -728,7 +724,7 @@ bool QBasicMutex::lockInternal(QDeadlineTimer deadlineTimer) QT_MUTEX_LOCK_NOEXC
} }
QMutexPrivate *d = static_cast<QMutexPrivate *>(copy); QMutexPrivate *d = static_cast<QMutexPrivate *>(copy);
if (remainingTime == 0 && !d->possiblyUnlocked.loadRelaxed()) if (deadlineTimer.hasExpired() && !d->possiblyUnlocked.loadRelaxed())
return false; return false;
// At this point we have a pointer to a QMutexPrivate. But the other thread // At this point we have a pointer to a QMutexPrivate. But the other thread
@ -790,7 +786,6 @@ bool QBasicMutex::lockInternal(QDeadlineTimer deadlineTimer) QT_MUTEX_LOCK_NOEXC
Q_ASSERT(d == d_ptr.loadRelaxed()); Q_ASSERT(d == d_ptr.loadRelaxed());
return true; return true;
} else { } else {
Q_ASSERT(remainingTime >= 0);
// timed out // timed out
d->derefWaiters(1); d->derefWaiters(1);
//There may be a race in which the mutex is unlocked right after we timed out, //There may be a race in which the mutex is unlocked right after we timed out,
@ -915,7 +910,7 @@ QT_END_NAMESPACE
#if defined(QT_ALWAYS_USE_FUTEX) #if defined(QT_ALWAYS_USE_FUTEX)
// nothing // nothing
#elif defined(Q_OS_MAC) #elif defined(Q_OS_DARWIN)
# include "qmutex_mac.cpp" # include "qmutex_mac.cpp"
#elif defined(Q_OS_WIN) #elif defined(Q_OS_WIN)
# include "qmutex_win.cpp" # include "qmutex_win.cpp"

View File

@ -95,22 +95,47 @@ using namespace Qt::StringLiterals;
/*! /*!
\variable QRhiD3D11NativeHandles::dev \variable QRhiD3D11NativeHandles::dev
Points to a
\l{https://learn.microsoft.com/en-us/windows/win32/api/d3d11/nn-d3d11-id3d11device}{ID3D11Device}
or left set to \nullptr if no existing device is to be imported.
\note When importing a device, both the device and the device context must be set to valid objects.
*/ */
/*! /*!
\variable QRhiD3D11NativeHandles::context \variable QRhiD3D11NativeHandles::context
Points to a \l{https://learn.microsoft.com/en-us/windows/win32/api/d3d11/nn-d3d11-id3d11devicecontext}{ID3D11DeviceContext}
or left set to \nullptr if no existing device context is to be imported.
\note When importing a device, both the device and the device context must be set to valid objects.
*/ */
/*! /*!
\variable QRhiD3D11NativeHandles::featureLevel \variable QRhiD3D11NativeHandles::featureLevel
Specifies the feature level passed to
\l{https://learn.microsoft.com/en-us/windows/win32/api/d3d11/nf-d3d11-d3d11createdevice}{D3D11CreateDevice()}.
Relevant only when QRhi creates the device, ignored when importing a device
and device context. When not set, the default rules outlined in the D3D
documentation apply.
*/ */
/*! /*!
\variable QRhiD3D11NativeHandles::adapterLuidLow \variable QRhiD3D11NativeHandles::adapterLuidLow
The low part of the local identifier (LUID) of the DXGI adapter to use.
Relevant only when QRhi creates the device, ignored when importing a device
and device context.
*/ */
/*! /*!
\variable QRhiD3D11NativeHandles::adapterLuidHigh \variable QRhiD3D11NativeHandles::adapterLuidHigh
The high part of the local identifier (LUID) of the DXGI adapter to use.
Relevant only when QRhi creates the device, ignored when importing a device
and device context.
*/ */
// help mingw with its ancient sdk headers // help mingw with its ancient sdk headers
@ -259,9 +284,7 @@ bool QRhiD3D11::create(QRhi::Flags flags)
if (!activeAdapter && (requestedAdapterIndex < 0 || requestedAdapterIndex == adapterIndex)) { if (!activeAdapter && (requestedAdapterIndex < 0 || requestedAdapterIndex == adapterIndex)) {
activeAdapter = adapter; activeAdapter = adapter;
adapterLuid = desc.AdapterLuid; adapterLuid = desc.AdapterLuid;
driverInfoStruct.deviceName = name.toUtf8(); QRhiD3D::fillDriverInfo(&driverInfoStruct, desc);
driverInfoStruct.deviceId = desc.DeviceId;
driverInfoStruct.vendorId = desc.VendorId;
qCDebug(QRHI_LOG_INFO, " using this adapter"); qCDebug(QRHI_LOG_INFO, " using this adapter");
} else { } else {
adapter->Release(); adapter->Release();
@ -304,21 +327,24 @@ bool QRhiD3D11::create(QRhi::Flags flags)
return false; return false;
} }
const bool supports11_1 = SUCCEEDED(ctx->QueryInterface(__uuidof(ID3D11DeviceContext1), reinterpret_cast<void **>(&context)));
ctx->Release();
if (!supports11_1) {
qWarning("ID3D11DeviceContext1 not supported");
return false;
}
// Test if creating a Shader Model 5.0 vertex shader works; we want to // Test if creating a Shader Model 5.0 vertex shader works; we want to
// fail already in create() if that's not the case. // fail already in create() if that's not the case.
ID3D11VertexShader *testShader = nullptr; ID3D11VertexShader *testShader = nullptr;
if (SUCCEEDED(dev->CreateVertexShader(g_testVertexShader, sizeof(g_testVertexShader), nullptr, &testShader))) { if (SUCCEEDED(dev->CreateVertexShader(g_testVertexShader, sizeof(g_testVertexShader), nullptr, &testShader))) {
testShader->Release(); testShader->Release();
} else { } else {
qWarning("D3D11 smoke test failed (failed to create vertex shader)"); static const char *msg = "D3D11 smoke test: Failed to create vertex shader";
ctx->Release(); if (flags.testFlag(QRhi::SuppressSmokeTestWarnings))
return false; qCDebug(QRHI_LOG_INFO, "%s", msg);
} else
qWarning("%s", msg);
const bool supports11_1 = SUCCEEDED(ctx->QueryInterface(__uuidof(ID3D11DeviceContext1), reinterpret_cast<void **>(&context)));
ctx->Release();
if (!supports11_1) {
qWarning("ID3D11DeviceContext1 not supported");
return false; return false;
} }
@ -328,11 +354,19 @@ bool QRhiD3D11::create(QRhi::Flags flags)
// still not support this D3D_FEATURE_LEVEL_11_1 feature. (e.g. // still not support this D3D_FEATURE_LEVEL_11_1 feature. (e.g.
// because it only does 11_0) // because it only does 11_0)
if (!features.ConstantBufferOffsetting) { if (!features.ConstantBufferOffsetting) {
qWarning("Constant buffer offsetting is not supported by the driver"); static const char *msg = "D3D11 smoke test: Constant buffer offsetting is not supported by the driver";
if (flags.testFlag(QRhi::SuppressSmokeTestWarnings))
qCDebug(QRHI_LOG_INFO, "%s", msg);
else
qWarning("%s", msg);
return false; return false;
} }
} else { } else {
qWarning("Failed to query D3D11_FEATURE_D3D11_OPTIONS"); static const char *msg = "D3D11 smoke test: Failed to query D3D11_FEATURE_D3D11_OPTIONS";
if (flags.testFlag(QRhi::SuppressSmokeTestWarnings))
qCDebug(QRHI_LOG_INFO, "%s", msg);
else
qWarning("%s", msg);
return false; return false;
} }
} else { } else {
@ -342,12 +376,14 @@ bool QRhiD3D11::create(QRhi::Flags flags)
if (SUCCEEDED(dev->QueryInterface(__uuidof(IDXGIDevice), reinterpret_cast<void **>(&dxgiDev)))) { if (SUCCEEDED(dev->QueryInterface(__uuidof(IDXGIDevice), reinterpret_cast<void **>(&dxgiDev)))) {
IDXGIAdapter *adapter = nullptr; IDXGIAdapter *adapter = nullptr;
if (SUCCEEDED(dxgiDev->GetAdapter(&adapter))) { if (SUCCEEDED(dxgiDev->GetAdapter(&adapter))) {
DXGI_ADAPTER_DESC desc; IDXGIAdapter1 *adapter1 = nullptr;
adapter->GetDesc(&desc); if (SUCCEEDED(adapter->QueryInterface(__uuidof(IDXGIAdapter1), reinterpret_cast<void **>(&adapter1)))) {
adapterLuid = desc.AdapterLuid; DXGI_ADAPTER_DESC1 desc;
driverInfoStruct.deviceName = QString::fromUtf16(reinterpret_cast<char16_t *>(desc.Description)).toUtf8(); adapter1->GetDesc1(&desc);
driverInfoStruct.deviceId = desc.DeviceId; adapterLuid = desc.AdapterLuid;
driverInfoStruct.vendorId = desc.VendorId; QRhiD3D::fillDriverInfo(&driverInfoStruct, desc);
adapter1->Release();
}
adapter->Release(); adapter->Release();
} }
dxgiDev->Release(); dxgiDev->Release();
@ -358,11 +394,6 @@ bool QRhiD3D11::create(QRhi::Flags flags)
if (FAILED(context->QueryInterface(__uuidof(ID3DUserDefinedAnnotation), reinterpret_cast<void **>(&annotations)))) if (FAILED(context->QueryInterface(__uuidof(ID3DUserDefinedAnnotation), reinterpret_cast<void **>(&annotations))))
annotations = nullptr; annotations = nullptr;
if (flags.testFlag(QRhi::EnableTimestamps)) {
ofr.timestamps.prepare(2, this);
// timestamp queries are optional so we can go on even if they failed
}
deviceLost = false; deviceLost = false;
nativeHandlesStruct.dev = dev; nativeHandlesStruct.dev = dev;
@ -388,7 +419,16 @@ void QRhiD3D11::destroy()
clearShaderCache(); clearShaderCache();
ofr.timestamps.destroy(); if (ofr.tsDisjointQuery) {
ofr.tsDisjointQuery->Release();
ofr.tsDisjointQuery = nullptr;
}
for (int i = 0; i < 2; ++i) {
if (ofr.tsQueries[i]) {
ofr.tsQueries[i]->Release();
ofr.tsQueries[i] = nullptr;
}
}
if (annotations) { if (annotations) {
annotations->Release(); annotations->Release();
@ -592,6 +632,8 @@ bool QRhiD3D11::isFeatureSupported(QRhi::Feature feature) const
return true; return true;
case QRhi::ThreeDimensionalTextureMipmaps: case QRhi::ThreeDimensionalTextureMipmaps:
return true; return true;
case QRhi::MultiView:
return false;
default: default:
Q_UNREACHABLE(); Q_UNREACHABLE();
return false; return false;
@ -1262,7 +1304,6 @@ const QRhiNativeHandles *QRhiD3D11::nativeHandles(QRhiCommandBuffer *cb)
void QRhiD3D11::beginExternal(QRhiCommandBuffer *cb) void QRhiD3D11::beginExternal(QRhiCommandBuffer *cb)
{ {
QD3D11CommandBuffer *cbD = QRHI_RES(QD3D11CommandBuffer, cb); QD3D11CommandBuffer *cbD = QRHI_RES(QD3D11CommandBuffer, cb);
// no timestampSwapChain, in order to avoid timestamp mess
executeCommandBuffer(cbD); executeCommandBuffer(cbD);
cbD->resetCommands(); cbD->resetCommands();
} }
@ -1285,6 +1326,19 @@ double QRhiD3D11::lastCompletedGpuTime(QRhiCommandBuffer *cb)
return cbD->lastGpuTime; return cbD->lastGpuTime;
} }
static inline QD3D11RenderTargetData *rtData(QRhiRenderTarget *rt)
{
switch (rt->resourceType()) {
case QRhiResource::SwapChainRenderTarget:
return &QRHI_RES(QD3D11SwapChainRenderTarget, rt)->d;
case QRhiResource::TextureRenderTarget:
return &QRHI_RES(QD3D11TextureRenderTarget, rt)->d;
default:
Q_UNREACHABLE();
return nullptr;
}
}
QRhi::FrameOpResult QRhiD3D11::beginFrame(QRhiSwapChain *swapChain, QRhi::BeginFrameFlags flags) QRhi::FrameOpResult QRhiD3D11::beginFrame(QRhiSwapChain *swapChain, QRhi::BeginFrameFlags flags)
{ {
Q_UNUSED(flags); Q_UNUSED(flags);
@ -1301,12 +1355,22 @@ QRhi::FrameOpResult QRhiD3D11::beginFrame(QRhiSwapChain *swapChain, QRhi::BeginF
finishActiveReadbacks(); finishActiveReadbacks();
if (swapChainD->timestamps.active[currentFrameSlot]) { if (swapChainD->timestamps.active[swapChainD->currentTimestampPairIndex]) {
double elapsedSec = 0; double elapsedSec = 0;
if (swapChainD->timestamps.tryQueryTimestamps(currentFrameSlot, context, &elapsedSec)) if (swapChainD->timestamps.tryQueryTimestamps(swapChainD->currentTimestampPairIndex, context, &elapsedSec))
swapChainD->cb.lastGpuTime = elapsedSec; swapChainD->cb.lastGpuTime = elapsedSec;
} }
ID3D11Query *tsStart = swapChainD->timestamps.query[swapChainD->currentTimestampPairIndex * 2];
ID3D11Query *tsDisjoint = swapChainD->timestamps.disjointQuery[swapChainD->currentTimestampPairIndex];
const bool recordTimestamps = tsStart && tsDisjoint && !swapChainD->timestamps.active[swapChainD->currentTimestampPairIndex];
QD3D11CommandBuffer::Command &cmd(swapChainD->cb.commands.get());
cmd.cmd = QD3D11CommandBuffer::Command::BeginFrame;
cmd.args.beginFrame.tsQuery = recordTimestamps ? tsStart : nullptr;
cmd.args.beginFrame.tsDisjointQuery = recordTimestamps ? tsDisjoint : nullptr;
cmd.args.beginFrame.swapchainData = rtData(&swapChainD->rt);
return QRhi::FrameOpSuccess; return QRhi::FrameOpSuccess;
} }
@ -1316,17 +1380,13 @@ QRhi::FrameOpResult QRhiD3D11::endFrame(QRhiSwapChain *swapChain, QRhi::EndFrame
Q_ASSERT(contextState.currentSwapChain = swapChainD); Q_ASSERT(contextState.currentSwapChain = swapChainD);
const int currentFrameSlot = swapChainD->currentFrameSlot; const int currentFrameSlot = swapChainD->currentFrameSlot;
ID3D11Query *tsDisjoint = swapChainD->timestamps.disjointQuery[currentFrameSlot]; QD3D11CommandBuffer::Command &cmd(swapChainD->cb.commands.get());
const int tsIdx = QD3D11SwapChain::BUFFER_COUNT * currentFrameSlot; cmd.cmd = QD3D11CommandBuffer::Command::EndFrame;
ID3D11Query *tsStart = swapChainD->timestamps.query[tsIdx]; cmd.args.endFrame.tsQuery = nullptr; // done later manually, see below
ID3D11Query *tsEnd = swapChainD->timestamps.query[tsIdx + 1]; cmd.args.endFrame.tsDisjointQuery = nullptr;
const bool recordTimestamps = tsDisjoint && tsStart && tsEnd && !swapChainD->timestamps.active[currentFrameSlot];
// send all commands to the context // send all commands to the context
if (recordTimestamps) executeCommandBuffer(&swapChainD->cb);
executeCommandBuffer(&swapChainD->cb, swapChainD);
else
executeCommandBuffer(&swapChainD->cb);
if (swapChainD->sampleDesc.Count > 1) { if (swapChainD->sampleDesc.Count > 1) {
context->ResolveSubresource(swapChainD->backBufferTex, 0, context->ResolveSubresource(swapChainD->backBufferTex, 0,
@ -1334,11 +1394,15 @@ QRhi::FrameOpResult QRhiD3D11::endFrame(QRhiSwapChain *swapChain, QRhi::EndFrame
swapChainD->colorFormat); swapChainD->colorFormat);
} }
// this is here because we want to include the time spent on the resolve as well // this is here because we want to include the time spent on the ResolveSubresource as well
ID3D11Query *tsEnd = swapChainD->timestamps.query[swapChainD->currentTimestampPairIndex * 2 + 1];
ID3D11Query *tsDisjoint = swapChainD->timestamps.disjointQuery[swapChainD->currentTimestampPairIndex];
const bool recordTimestamps = tsEnd && tsDisjoint && !swapChainD->timestamps.active[swapChainD->currentTimestampPairIndex];
if (recordTimestamps) { if (recordTimestamps) {
context->End(tsEnd); context->End(tsEnd);
context->End(tsDisjoint); context->End(tsDisjoint);
swapChainD->timestamps.active[currentFrameSlot] = true; swapChainD->timestamps.active[swapChainD->currentTimestampPairIndex] = true;
swapChainD->currentTimestampPairIndex = (swapChainD->currentTimestampPairIndex + 1) % QD3D11SwapChainTimestamps::TIMESTAMP_PAIRS;
} }
if (!flags.testFlag(QRhi::SkipPresent)) { if (!flags.testFlag(QRhi::SkipPresent)) {
@ -1383,12 +1447,36 @@ QRhi::FrameOpResult QRhiD3D11::beginOffscreenFrame(QRhiCommandBuffer **cb, QRhi:
ofr.cbWrapper.resetState(); ofr.cbWrapper.resetState();
*cb = &ofr.cbWrapper; *cb = &ofr.cbWrapper;
if (ofr.timestamps.active[ofr.timestampIdx]) { if (rhiFlags.testFlag(QRhi::EnableTimestamps)) {
double elapsedSec = 0; D3D11_QUERY_DESC queryDesc = {};
if (ofr.timestamps.tryQueryTimestamps(ofr.timestampIdx, context, &elapsedSec)) if (!ofr.tsDisjointQuery) {
ofr.cbWrapper.lastGpuTime = elapsedSec; queryDesc.Query = D3D11_QUERY_TIMESTAMP_DISJOINT;
HRESULT hr = dev->CreateQuery(&queryDesc, &ofr.tsDisjointQuery);
if (FAILED(hr)) {
qWarning("Failed to create timestamp disjoint query: %s",
qPrintable(QSystemError::windowsComString(hr)));
return QRhi::FrameOpError;
}
}
queryDesc.Query = D3D11_QUERY_TIMESTAMP;
for (int i = 0; i < 2; ++i) {
if (!ofr.tsQueries[i]) {
HRESULT hr = dev->CreateQuery(&queryDesc, &ofr.tsQueries[i]);
if (FAILED(hr)) {
qWarning("Failed to create timestamp query: %s",
qPrintable(QSystemError::windowsComString(hr)));
return QRhi::FrameOpError;
}
}
}
} }
QD3D11CommandBuffer::Command &cmd(ofr.cbWrapper.commands.get());
cmd.cmd = QD3D11CommandBuffer::Command::BeginFrame;
cmd.args.beginFrame.tsQuery = ofr.tsQueries[0] ? ofr.tsQueries[0] : nullptr;
cmd.args.beginFrame.tsDisjointQuery = ofr.tsDisjointQuery ? ofr.tsDisjointQuery : nullptr;
cmd.args.beginFrame.swapchainData = nullptr;
return QRhi::FrameOpSuccess; return QRhi::FrameOpSuccess;
} }
@ -1397,25 +1485,39 @@ QRhi::FrameOpResult QRhiD3D11::endOffscreenFrame(QRhi::EndFrameFlags flags)
Q_UNUSED(flags); Q_UNUSED(flags);
ofr.active = false; ofr.active = false;
ID3D11Query *tsDisjoint = ofr.timestamps.disjointQuery[ofr.timestampIdx]; QD3D11CommandBuffer::Command &cmd(ofr.cbWrapper.commands.get());
ID3D11Query *tsStart = ofr.timestamps.query[ofr.timestampIdx * 2]; cmd.cmd = QD3D11CommandBuffer::Command::EndFrame;
ID3D11Query *tsEnd = ofr.timestamps.query[ofr.timestampIdx * 2 + 1]; cmd.args.endFrame.tsQuery = ofr.tsQueries[1] ? ofr.tsQueries[1] : nullptr;
const bool recordTimestamps = tsDisjoint && tsStart && tsEnd && !ofr.timestamps.active[ofr.timestampIdx]; cmd.args.endFrame.tsDisjointQuery = ofr.tsDisjointQuery ? ofr.tsDisjointQuery : nullptr;
if (recordTimestamps) {
context->Begin(tsDisjoint);
context->End(tsStart); // record timestamp; no Begin() for D3D11_QUERY_TIMESTAMP
}
executeCommandBuffer(&ofr.cbWrapper); executeCommandBuffer(&ofr.cbWrapper);
context->Flush(); context->Flush();
finishActiveReadbacks(); finishActiveReadbacks();
if (recordTimestamps) { if (ofr.tsQueries[0]) {
context->End(tsEnd); quint64 timestamps[2];
context->End(tsDisjoint); D3D11_QUERY_DATA_TIMESTAMP_DISJOINT dj;
ofr.timestamps.active[ofr.timestampIdx] = true; HRESULT hr;
ofr.timestampIdx = (ofr.timestampIdx + 1) % 2; bool ok = true;
do {
hr = context->GetData(ofr.tsDisjointQuery, &dj, sizeof(dj), 0);
} while (hr == S_FALSE);
ok &= hr == S_OK;
do {
hr = context->GetData(ofr.tsQueries[1], &timestamps[1], sizeof(quint64), 0);
} while (hr == S_FALSE);
ok &= hr == S_OK;
do {
hr = context->GetData(ofr.tsQueries[0], &timestamps[0], sizeof(quint64), 0);
} while (hr == S_FALSE);
ok &= hr == S_OK;
if (ok) {
if (!dj.Disjoint && dj.Frequency) {
const float elapsedMs = (timestamps[1] - timestamps[0]) / float(dj.Frequency) * 1000.0f;
ofr.cbWrapper.lastGpuTime = elapsedMs / 1000.0;
}
}
} }
return QRhi::FrameOpSuccess; return QRhi::FrameOpSuccess;
@ -1558,7 +1660,7 @@ QRhi::FrameOpResult QRhiD3D11::finish()
} else { } else {
Q_ASSERT(contextState.currentSwapChain); Q_ASSERT(contextState.currentSwapChain);
Q_ASSERT(contextState.currentSwapChain->cb.recordingPass == QD3D11CommandBuffer::NoPass); Q_ASSERT(contextState.currentSwapChain->cb.recordingPass == QD3D11CommandBuffer::NoPass);
executeCommandBuffer(&contextState.currentSwapChain->cb); // no timestampSwapChain, in order to avoid timestamp mess executeCommandBuffer(&contextState.currentSwapChain->cb);
contextState.currentSwapChain->cb.resetCommands(); contextState.currentSwapChain->cb.resetCommands();
} }
} }
@ -1933,19 +2035,6 @@ void QRhiD3D11::finishActiveReadbacks()
f(); f();
} }
static inline QD3D11RenderTargetData *rtData(QRhiRenderTarget *rt)
{
switch (rt->resourceType()) {
case QRhiResource::SwapChainRenderTarget:
return &QRHI_RES(QD3D11SwapChainRenderTarget, rt)->d;
case QRhiResource::TextureRenderTarget:
return &QRHI_RES(QD3D11TextureRenderTarget, rt)->d;
default:
Q_UNREACHABLE();
return nullptr;
}
}
void QRhiD3D11::resourceUpdate(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) void QRhiD3D11::resourceUpdate(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates)
{ {
Q_ASSERT(QRHI_RES(QD3D11CommandBuffer, cb)->recordingPass == QD3D11CommandBuffer::NoPass); Q_ASSERT(QRHI_RES(QD3D11CommandBuffer, cb)->recordingPass == QD3D11CommandBuffer::NoPass);
@ -2651,7 +2740,7 @@ void QRhiD3D11::resetShaderResources()
currentShaderMask &= ~StageU##MaskBit; \ currentShaderMask &= ~StageU##MaskBit; \
} }
void QRhiD3D11::executeCommandBuffer(QD3D11CommandBuffer *cbD, QD3D11SwapChain *timestampSwapChain) void QRhiD3D11::executeCommandBuffer(QD3D11CommandBuffer *cbD)
{ {
quint32 stencilRef = 0; quint32 stencilRef = 0;
float blendConstants[] = { 1, 1, 1, 1 }; float blendConstants[] = { 1, 1, 1, 1 };
@ -2664,26 +2753,30 @@ void QRhiD3D11::executeCommandBuffer(QD3D11CommandBuffer *cbD, QD3D11SwapChain *
}; };
int currentShaderMask = 0xFF; int currentShaderMask = 0xFF;
if (timestampSwapChain) {
const int currentFrameSlot = timestampSwapChain->currentFrameSlot;
ID3D11Query *tsDisjoint = timestampSwapChain->timestamps.disjointQuery[currentFrameSlot];
const int tsIdx = QD3D11SwapChain::BUFFER_COUNT * currentFrameSlot;
ID3D11Query *tsStart = timestampSwapChain->timestamps.query[tsIdx];
if (tsDisjoint && tsStart && !timestampSwapChain->timestamps.active[currentFrameSlot]) {
// The timestamps seem to include vsync time with Present(1), except
// when running on a non-primary gpu. This is not ideal. So try working
// it around by issuing a semi-fake OMSetRenderTargets early and
// writing the first timestamp only afterwards.
context->Begin(tsDisjoint);
QD3D11RenderTargetData *rtD = rtData(&timestampSwapChain->rt);
context->OMSetRenderTargets(UINT(rtD->colorAttCount), rtD->colorAttCount ? rtD->rtv : nullptr, rtD->dsv);
context->End(tsStart); // just record a timestamp, no Begin needed
}
}
for (auto it = cbD->commands.cbegin(), end = cbD->commands.cend(); it != end; ++it) { for (auto it = cbD->commands.cbegin(), end = cbD->commands.cend(); it != end; ++it) {
const QD3D11CommandBuffer::Command &cmd(*it); const QD3D11CommandBuffer::Command &cmd(*it);
switch (cmd.cmd) { switch (cmd.cmd) {
case QD3D11CommandBuffer::Command::BeginFrame:
if (cmd.args.beginFrame.tsDisjointQuery)
context->Begin(cmd.args.beginFrame.tsDisjointQuery);
if (cmd.args.beginFrame.tsQuery) {
if (cmd.args.beginFrame.swapchainData) {
// The timestamps seem to include vsync time with Present(1), except
// when running on a non-primary gpu. This is not ideal. So try working
// it around by issuing a semi-fake OMSetRenderTargets early and
// writing the first timestamp only afterwards.
QD3D11RenderTargetData *rtD = cmd.args.beginFrame.swapchainData;
context->OMSetRenderTargets(UINT(rtD->colorAttCount), rtD->colorAttCount ? rtD->rtv : nullptr, rtD->dsv);
}
context->End(cmd.args.beginFrame.tsQuery); // no Begin() for D3D11_QUERY_TIMESTAMP
}
break;
case QD3D11CommandBuffer::Command::EndFrame:
if (cmd.args.endFrame.tsQuery)
context->End(cmd.args.endFrame.tsQuery);
if (cmd.args.endFrame.tsDisjointQuery)
context->End(cmd.args.endFrame.tsDisjointQuery);
break;
case QD3D11CommandBuffer::Command::ResetShaderResources: case QD3D11CommandBuffer::Command::ResetShaderResources:
resetShaderResources(); resetShaderResources();
break; break;
@ -4702,14 +4795,13 @@ void QD3D11CommandBuffer::destroy()
// nothing to do here // nothing to do here
} }
bool QD3D11Timestamps::prepare(int pairCount, QRhiD3D11 *rhiD) bool QD3D11SwapChainTimestamps::prepare(QRhiD3D11 *rhiD)
{ {
// Creates the query objects if not yet done, but otherwise calling this // Creates the query objects if not yet done, but otherwise calling this
// function is expected to be a no-op. // function is expected to be a no-op.
Q_ASSERT(pairCount <= MAX_TIMESTAMP_PAIRS);
D3D11_QUERY_DESC queryDesc = {}; D3D11_QUERY_DESC queryDesc = {};
for (int i = 0; i < pairCount; ++i) { for (int i = 0; i < TIMESTAMP_PAIRS; ++i) {
if (!disjointQuery[i]) { if (!disjointQuery[i]) {
queryDesc.Query = D3D11_QUERY_TIMESTAMP_DISJOINT; queryDesc.Query = D3D11_QUERY_TIMESTAMP_DISJOINT;
HRESULT hr = rhiD->dev->CreateQuery(&queryDesc, &disjointQuery[i]); HRESULT hr = rhiD->dev->CreateQuery(&queryDesc, &disjointQuery[i]);
@ -4721,7 +4813,7 @@ bool QD3D11Timestamps::prepare(int pairCount, QRhiD3D11 *rhiD)
} }
queryDesc.Query = D3D11_QUERY_TIMESTAMP; queryDesc.Query = D3D11_QUERY_TIMESTAMP;
for (int j = 0; j < 2; ++j) { for (int j = 0; j < 2; ++j) {
const int idx = pairCount * i + j; const int idx = 2 * i + j;
if (!query[idx]) { if (!query[idx]) {
HRESULT hr = rhiD->dev->CreateQuery(&queryDesc, &query[idx]); HRESULT hr = rhiD->dev->CreateQuery(&queryDesc, &query[idx]);
if (FAILED(hr)) { if (FAILED(hr)) {
@ -4732,20 +4824,19 @@ bool QD3D11Timestamps::prepare(int pairCount, QRhiD3D11 *rhiD)
} }
} }
} }
this->pairCount = pairCount;
return true; return true;
} }
void QD3D11Timestamps::destroy() void QD3D11SwapChainTimestamps::destroy()
{ {
for (int i = 0; i < MAX_TIMESTAMP_PAIRS; ++i) { for (int i = 0; i < TIMESTAMP_PAIRS; ++i) {
active[i] = false; active[i] = false;
if (disjointQuery[i]) { if (disjointQuery[i]) {
disjointQuery[i]->Release(); disjointQuery[i]->Release();
disjointQuery[i] = nullptr; disjointQuery[i] = nullptr;
} }
for (int j = 0; j < 2; ++j) { for (int j = 0; j < 2; ++j) {
const int idx = MAX_TIMESTAMP_PAIRS * i + j; const int idx = TIMESTAMP_PAIRS * i + j;
if (query[idx]) { if (query[idx]) {
query[idx]->Release(); query[idx]->Release();
query[idx] = nullptr; query[idx] = nullptr;
@ -4754,26 +4845,21 @@ void QD3D11Timestamps::destroy()
} }
} }
bool QD3D11Timestamps::tryQueryTimestamps(int idx, ID3D11DeviceContext *context, double *elapsedSec) bool QD3D11SwapChainTimestamps::tryQueryTimestamps(int pairIndex, ID3D11DeviceContext *context, double *elapsedSec)
{ {
bool result = false; bool result = false;
if (!active[idx]) if (!active[pairIndex])
return result; return result;
ID3D11Query *tsDisjoint = disjointQuery[idx]; ID3D11Query *tsDisjoint = disjointQuery[pairIndex];
const int tsIdx = pairCount * idx; ID3D11Query *tsStart = query[pairIndex * 2];
ID3D11Query *tsStart = query[tsIdx]; ID3D11Query *tsEnd = query[pairIndex * 2 + 1];
ID3D11Query *tsEnd = query[tsIdx + 1];
quint64 timestamps[2]; quint64 timestamps[2];
D3D11_QUERY_DATA_TIMESTAMP_DISJOINT dj; D3D11_QUERY_DATA_TIMESTAMP_DISJOINT dj;
bool ok = true; bool ok = true;
ok &= context->GetData(tsDisjoint, &dj, sizeof(dj), D3D11_ASYNC_GETDATA_DONOTFLUSH) == S_OK; ok &= context->GetData(tsDisjoint, &dj, sizeof(dj), D3D11_ASYNC_GETDATA_DONOTFLUSH) == S_OK;
ok &= context->GetData(tsEnd, &timestamps[1], sizeof(quint64), D3D11_ASYNC_GETDATA_DONOTFLUSH) == S_OK; ok &= context->GetData(tsEnd, &timestamps[1], sizeof(quint64), D3D11_ASYNC_GETDATA_DONOTFLUSH) == S_OK;
// this above is often not ready, not even in frame_where_recorded+2,
// not clear why. so make the whole thing async and do not touch the
// queries until they are finally all available in frame this+2 or
// this+4 or ...
ok &= context->GetData(tsStart, &timestamps[0], sizeof(quint64), D3D11_ASYNC_GETDATA_DONOTFLUSH) == S_OK; ok &= context->GetData(tsStart, &timestamps[0], sizeof(quint64), D3D11_ASYNC_GETDATA_DONOTFLUSH) == S_OK;
if (ok) { if (ok) {
@ -4782,16 +4868,14 @@ bool QD3D11Timestamps::tryQueryTimestamps(int idx, ID3D11DeviceContext *context,
*elapsedSec = elapsedMs / 1000.0; *elapsedSec = elapsedMs / 1000.0;
result = true; result = true;
} }
active[idx] = false; active[pairIndex] = false;
} // else leave active set, will retry in a subsequent beginFrame or similar } // else leave active set, will retry in a subsequent beginFrame
return result; return result;
} }
QD3D11SwapChain::QD3D11SwapChain(QRhiImplementation *rhi) QD3D11SwapChain::QD3D11SwapChain(QRhiImplementation *rhi)
: QRhiSwapChain(rhi), : QRhiSwapChain(rhi), rt(rhi, this), rtRight(rhi, this), cb(rhi)
rt(rhi, this),
cb(rhi)
{ {
backBufferTex = nullptr; backBufferTex = nullptr;
backBufferRtv = nullptr; backBufferRtv = nullptr;
@ -4812,6 +4896,10 @@ void QD3D11SwapChain::releaseBuffers()
backBufferRtv->Release(); backBufferRtv->Release();
backBufferRtv = nullptr; backBufferRtv = nullptr;
} }
if (backBufferRtvRight) {
backBufferRtvRight->Release();
backBufferRtvRight = nullptr;
}
if (backBufferTex) { if (backBufferTex) {
backBufferTex->Release(); backBufferTex->Release();
backBufferTex = nullptr; backBufferTex = nullptr;
@ -4869,50 +4957,17 @@ QRhiRenderTarget *QD3D11SwapChain::currentFrameRenderTarget()
return &rt; return &rt;
} }
QRhiRenderTarget *QD3D11SwapChain::currentFrameRenderTarget(StereoTargetBuffer targetBuffer)
{
return targetBuffer == StereoTargetBuffer::LeftBuffer? &rt: &rtRight;
}
QSize QD3D11SwapChain::surfacePixelSize() QSize QD3D11SwapChain::surfacePixelSize()
{ {
Q_ASSERT(m_window); Q_ASSERT(m_window);
return m_window->size() * m_window->devicePixelRatio(); return m_window->size() * m_window->devicePixelRatio();
} }
static bool output6ForWindow(QWindow *w, IDXGIAdapter1 *adapter, IDXGIOutput6 **result)
{
bool ok = false;
QRect wr = w->geometry();
wr = QRect(wr.topLeft() * w->devicePixelRatio(), wr.size() * w->devicePixelRatio());
const QPoint center = wr.center();
IDXGIOutput *currentOutput = nullptr;
IDXGIOutput *output = nullptr;
for (UINT i = 0; adapter->EnumOutputs(i, &output) != DXGI_ERROR_NOT_FOUND; ++i) {
DXGI_OUTPUT_DESC desc;
output->GetDesc(&desc);
const RECT r = desc.DesktopCoordinates;
const QRect dr(QPoint(r.left, r.top), QPoint(r.right - 1, r.bottom - 1));
if (dr.contains(center)) {
currentOutput = output;
break;
} else {
output->Release();
}
}
if (currentOutput) {
ok = SUCCEEDED(currentOutput->QueryInterface(__uuidof(IDXGIOutput6), reinterpret_cast<void **>(result)));
currentOutput->Release();
}
return ok;
}
static bool outputDesc1ForWindow(QWindow *w, IDXGIAdapter1 *adapter, DXGI_OUTPUT_DESC1 *result)
{
bool ok = false;
IDXGIOutput6 *out6 = nullptr;
if (output6ForWindow(w, adapter, &out6)) {
ok = SUCCEEDED(out6->GetDesc1(result));
out6->Release();
}
return ok;
}
bool QD3D11SwapChain::isFormatSupported(Format f) bool QD3D11SwapChain::isFormatSupported(Format f)
{ {
if (f == SDR) if (f == SDR)
@ -4925,7 +4980,7 @@ bool QD3D11SwapChain::isFormatSupported(Format f)
QRHI_RES_RHI(QRhiD3D11); QRHI_RES_RHI(QRhiD3D11);
DXGI_OUTPUT_DESC1 desc1; DXGI_OUTPUT_DESC1 desc1;
if (outputDesc1ForWindow(m_window, rhiD->activeAdapter, &desc1)) { if (QRhiD3D::outputDesc1ForWindow(m_window, rhiD->activeAdapter, &desc1)) {
if (desc1.ColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020) if (desc1.ColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020)
return f == QRhiSwapChain::HDRExtendedSrgbLinear || f == QRhiSwapChain::HDR10; return f == QRhiSwapChain::HDRExtendedSrgbLinear || f == QRhiSwapChain::HDR10;
} }
@ -4936,14 +4991,16 @@ bool QD3D11SwapChain::isFormatSupported(Format f)
QRhiSwapChainHdrInfo QD3D11SwapChain::hdrInfo() QRhiSwapChainHdrInfo QD3D11SwapChain::hdrInfo()
{ {
QRhiSwapChainHdrInfo info = QRhiSwapChain::hdrInfo(); QRhiSwapChainHdrInfo info = QRhiSwapChain::hdrInfo();
// Must use m_window, not window, given this may be called before createOrResize().
if (m_window) { if (m_window) {
QRHI_RES_RHI(QRhiD3D11); QRHI_RES_RHI(QRhiD3D11);
DXGI_OUTPUT_DESC1 hdrOutputDesc; DXGI_OUTPUT_DESC1 hdrOutputDesc;
if (outputDesc1ForWindow(m_window, rhiD->activeAdapter, &hdrOutputDesc)) { if (QRhiD3D::outputDesc1ForWindow(m_window, rhiD->activeAdapter, &hdrOutputDesc)) {
info.isHardCodedDefaults = false;
info.limitsType = QRhiSwapChainHdrInfo::LuminanceInNits; info.limitsType = QRhiSwapChainHdrInfo::LuminanceInNits;
info.limits.luminanceInNits.minLuminance = hdrOutputDesc.MinLuminance; info.limits.luminanceInNits.minLuminance = hdrOutputDesc.MinLuminance;
info.limits.luminanceInNits.maxLuminance = hdrOutputDesc.MaxLuminance; info.limits.luminanceInNits.maxLuminance = hdrOutputDesc.MaxLuminance;
info.luminanceBehavior = QRhiSwapChainHdrInfo::SceneReferred; // 1.0 = 80 nits
info.sdrWhiteLevel = QRhiD3D::sdrWhiteLevelInNits(hdrOutputDesc);
} }
} }
return info; return info;
@ -5016,11 +5073,13 @@ bool QD3D11SwapChain::createOrResize()
{ {
return createOrResizeWin7(); return createOrResizeWin7();
} }
// Can be called multiple times due to window resizes - that is not the // 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 // same as a simple destroy+create (as with other resources). Just need to
// resize the buffers then. // resize the buffers then.
const bool needsRegistration = !window || window != m_window; const bool needsRegistration = !window || window != m_window;
const bool stereo = m_window->format().stereo();
// except if the window actually changes // except if the window actually changes
if (window && window != m_window) if (window && window != m_window)
@ -5078,7 +5137,7 @@ bool QD3D11SwapChain::createOrResize()
DXGI_COLOR_SPACE_TYPE hdrColorSpace = DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709; // SDR DXGI_COLOR_SPACE_TYPE hdrColorSpace = DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709; // SDR
DXGI_OUTPUT_DESC1 hdrOutputDesc; DXGI_OUTPUT_DESC1 hdrOutputDesc;
if (outputDesc1ForWindow(m_window, rhiD->activeAdapter, &hdrOutputDesc) && m_format != SDR) { if (QRhiD3D::outputDesc1ForWindow(m_window, rhiD->activeAdapter, &hdrOutputDesc) && m_format != SDR) {
// https://docs.microsoft.com/en-us/windows/win32/direct3darticles/high-dynamic-range // https://docs.microsoft.com/en-us/windows/win32/direct3darticles/high-dynamic-range
if (hdrOutputDesc.ColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020) { if (hdrOutputDesc.ColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020) {
switch (m_format) { switch (m_format) {
@ -5120,6 +5179,7 @@ bool QD3D11SwapChain::createOrResize()
desc.Flags = swapChainFlags; desc.Flags = swapChainFlags;
desc.Scaling = rhiD->useLegacySwapchainModel ? DXGI_SCALING_STRETCH : DXGI_SCALING_NONE; desc.Scaling = rhiD->useLegacySwapchainModel ? DXGI_SCALING_STRETCH : DXGI_SCALING_NONE;
desc.SwapEffect = rhiD->useLegacySwapchainModel ? DXGI_SWAP_EFFECT_DISCARD : DXGI_SWAP_EFFECT_FLIP_DISCARD; desc.SwapEffect = rhiD->useLegacySwapchainModel ? DXGI_SWAP_EFFECT_DISCARD : DXGI_SWAP_EFFECT_FLIP_DISCARD;
desc.Stereo = stereo;
if (dcompVisual) { if (dcompVisual) {
// With DirectComposition setting AlphaMode to STRAIGHT fails the // With DirectComposition setting AlphaMode to STRAIGHT fails the
@ -5238,6 +5298,19 @@ bool QD3D11SwapChain::createOrResize()
return false; return false;
} }
if (stereo) {
// Create a second render target view for the right eye
rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY;
rtvDesc.Texture2DArray.FirstArraySlice = 1;
rtvDesc.Texture2DArray.ArraySize = 1;
hr = rhiD->dev->CreateRenderTargetView(backBufferTex, &rtvDesc, &backBufferRtvRight);
if (FAILED(hr)) {
qWarning("Failed to create rtv for swapchain backbuffer (right eye): %s",
qPrintable(QSystemError::windowsComString(hr)));
return false;
}
}
// Try to reduce stalls by having a dedicated MSAA texture per swapchain buffer. // Try to reduce stalls by having a dedicated MSAA texture per swapchain buffer.
for (int i = 0; i < BUFFER_COUNT; ++i) { for (int i = 0; i < BUFFER_COUNT; ++i) {
if (sampleDesc.Count > 1) { if (sampleDesc.Count > 1) {
@ -5276,8 +5349,20 @@ bool QD3D11SwapChain::createOrResize()
rtD->d.colorAttCount = 1; rtD->d.colorAttCount = 1;
rtD->d.dsAttCount = m_depthStencil ? 1 : 0; rtD->d.dsAttCount = m_depthStencil ? 1 : 0;
if (stereo) {
rtD = QRHI_RES(QD3D11SwapChainRenderTarget, &rtRight);
rtD->d.rp = QRHI_RES(QD3D11RenderPassDescriptor, m_renderPassDesc);
rtD->d.pixelSize = pixelSize;
rtD->d.dpr = float(window->devicePixelRatio());
rtD->d.sampleCount = int(sampleDesc.Count);
rtD->d.colorAttCount = 1;
rtD->d.dsAttCount = m_depthStencil ? 1 : 0;
rtD->d.rtv[0] = backBufferRtvRight;
rtD->d.dsv = ds ? ds->dsv : nullptr;
}
if (rhiD->rhiFlags.testFlag(QRhi::EnableTimestamps)) { if (rhiD->rhiFlags.testFlag(QRhi::EnableTimestamps)) {
timestamps.prepare(BUFFER_COUNT, rhiD); timestamps.prepare(rhiD);
// timestamp queries are optional so we can go on even if they failed // timestamp queries are optional so we can go on even if they failed
} }

View File

@ -356,6 +356,8 @@ struct QD3D11CommandBuffer : public QRhiCommandBuffer
struct Command { struct Command {
enum Cmd { enum Cmd {
BeginFrame,
EndFrame,
ResetShaderResources, ResetShaderResources,
SetRenderTarget, SetRenderTarget,
Clear, Clear,
@ -385,6 +387,15 @@ struct QD3D11CommandBuffer : public QRhiCommandBuffer
// QRhi*/QD3D11* references should be kept at minimum (so no // QRhi*/QD3D11* references should be kept at minimum (so no
// QRhiTexture/Buffer/etc. pointers). // QRhiTexture/Buffer/etc. pointers).
union Args { union Args {
struct {
ID3D11Query *tsQuery;
ID3D11Query *tsDisjointQuery;
QD3D11RenderTargetData *swapchainData;
} beginFrame;
struct {
ID3D11Query *tsQuery;
ID3D11Query *tsDisjointQuery;
} endFrame;
struct { struct {
QRhiRenderTarget *rt; QRhiRenderTarget *rt;
} setRenderTarget; } setRenderTarget;
@ -556,17 +567,15 @@ struct QD3D11CommandBuffer : public QRhiCommandBuffer
} }
}; };
static const int QD3D11_SWAPCHAIN_BUFFER_COUNT = 2; struct QD3D11SwapChainTimestamps
struct QD3D11Timestamps
{ {
static const int MAX_TIMESTAMP_PAIRS = QD3D11_SWAPCHAIN_BUFFER_COUNT; static const int TIMESTAMP_PAIRS = 2;
bool active[MAX_TIMESTAMP_PAIRS] = {};
ID3D11Query *disjointQuery[MAX_TIMESTAMP_PAIRS] = {};
ID3D11Query *query[MAX_TIMESTAMP_PAIRS * 2] = {};
int pairCount = 0;
bool prepare(int pairCount, QRhiD3D11 *rhiD); bool active[TIMESTAMP_PAIRS] = {};
ID3D11Query *disjointQuery[TIMESTAMP_PAIRS] = {};
ID3D11Query *query[TIMESTAMP_PAIRS * 2] = {};
bool prepare(QRhiD3D11 *rhiD);
void destroy(); void destroy();
bool tryQueryTimestamps(int idx, ID3D11DeviceContext *context, double *elapsedSec); bool tryQueryTimestamps(int idx, ID3D11DeviceContext *context, double *elapsedSec);
}; };
@ -579,6 +588,7 @@ struct QD3D11SwapChain : public QRhiSwapChain
QRhiCommandBuffer *currentFrameCommandBuffer() override; QRhiCommandBuffer *currentFrameCommandBuffer() override;
QRhiRenderTarget *currentFrameRenderTarget() override; QRhiRenderTarget *currentFrameRenderTarget() override;
QRhiRenderTarget *currentFrameRenderTarget(StereoTargetBuffer targetBuffer) override;
QSize surfacePixelSize() override; QSize surfacePixelSize() override;
bool isFormatSupported(Format f) override; bool isFormatSupported(Format f) override;
@ -595,6 +605,7 @@ struct QD3D11SwapChain : public QRhiSwapChain
QWindow *window = nullptr; QWindow *window = nullptr;
QSize pixelSize; QSize pixelSize;
QD3D11SwapChainRenderTarget rt; QD3D11SwapChainRenderTarget rt;
QD3D11SwapChainRenderTarget rtRight;
QD3D11CommandBuffer cb; QD3D11CommandBuffer cb;
DXGI_FORMAT colorFormat; DXGI_FORMAT colorFormat;
DXGI_FORMAT srgbAdjustedColorFormat; DXGI_FORMAT srgbAdjustedColorFormat;
@ -602,7 +613,8 @@ struct QD3D11SwapChain : public QRhiSwapChain
UINT swapChainFlags = 0; UINT swapChainFlags = 0;
ID3D11Texture2D *backBufferTex; ID3D11Texture2D *backBufferTex;
ID3D11RenderTargetView *backBufferRtv; ID3D11RenderTargetView *backBufferRtv;
static const int BUFFER_COUNT = QD3D11_SWAPCHAIN_BUFFER_COUNT; ID3D11RenderTargetView *backBufferRtvRight = nullptr;
static const int BUFFER_COUNT = 2;
ID3D11Texture2D *msaaTex[BUFFER_COUNT]; ID3D11Texture2D *msaaTex[BUFFER_COUNT];
ID3D11RenderTargetView *msaaRtv[BUFFER_COUNT]; ID3D11RenderTargetView *msaaRtv[BUFFER_COUNT];
DXGI_SAMPLE_DESC sampleDesc; DXGI_SAMPLE_DESC sampleDesc;
@ -612,7 +624,8 @@ struct QD3D11SwapChain : public QRhiSwapChain
UINT swapInterval = 1; UINT swapInterval = 1;
IDCompositionTarget *dcompTarget = nullptr; IDCompositionTarget *dcompTarget = nullptr;
IDCompositionVisual *dcompVisual = nullptr; IDCompositionVisual *dcompVisual = nullptr;
QD3D11Timestamps timestamps; QD3D11SwapChainTimestamps timestamps;
int currentTimestampPairIndex = 0;
}; };
class QRhiD3D11 : public QRhiImplementation class QRhiD3D11 : public QRhiImplementation
@ -737,7 +750,7 @@ public:
const uint *dynOfsPairs, int dynOfsPairCount, const uint *dynOfsPairs, int dynOfsPairCount,
bool offsetOnlyChange); bool offsetOnlyChange);
void resetShaderResources(); void resetShaderResources();
void executeCommandBuffer(QD3D11CommandBuffer *cbD, QD3D11SwapChain *timestampSwapChain = nullptr); void executeCommandBuffer(QD3D11CommandBuffer *cbD);
DXGI_SAMPLE_DESC effectiveSampleDesc(int sampleCount) const; DXGI_SAMPLE_DESC effectiveSampleDesc(int sampleCount) const;
void finishActiveReadbacks(); void finishActiveReadbacks();
void reportLiveObjects(ID3D11Device *device); void reportLiveObjects(ID3D11Device *device);
@ -780,8 +793,8 @@ public:
OffscreenFrame(QRhiImplementation *rhi) : cbWrapper(rhi) { } OffscreenFrame(QRhiImplementation *rhi) : cbWrapper(rhi) { }
bool active = false; bool active = false;
QD3D11CommandBuffer cbWrapper; QD3D11CommandBuffer cbWrapper;
QD3D11Timestamps timestamps; ID3D11Query *tsQueries[2] = {};
int timestampIdx = 0; ID3D11Query *tsDisjointQuery = nullptr;
} ofr; } ofr;
struct TextureReadback { struct TextureReadback {

File diff suppressed because it is too large Load Diff

View File

@ -359,10 +359,10 @@ namespace {
{ {
} }
inline void addKey(const void *key, const QByteArray &fontData) inline void addKey(const QByteArray &fontData)
{ {
Q_ASSERT(!m_fontDatas.contains(key)); if (!m_fontDatas.contains(fontData.data()))
m_fontDatas.insert(key, fontData); m_fontDatas.insert(fontData.data(), fontData);
} }
inline void removeKey(const void *key) inline void removeKey(const void *key)
@ -378,6 +378,11 @@ namespace {
UINT32 fontFileReferenceKeySize, UINT32 fontFileReferenceKeySize,
OUT IDWriteFontFileStream **fontFileStream) override; OUT IDWriteFontFileStream **fontFileStream) override;
void clear()
{
m_fontDatas.clear();
}
private: private:
ULONG m_referenceCount; ULONG m_referenceCount;
QHash<const void *, QByteArray> m_fontDatas; QHash<const void *, QByteArray> m_fontDatas;
@ -435,53 +440,63 @@ namespace {
return S_OK; return S_OK;
} }
class CustomFontFileLoader
{
public:
CustomFontFileLoader(IDWriteFactory *factory)
{
m_directWriteFactory = factory;
if (m_directWriteFactory) {
m_directWriteFactory->AddRef();
m_directWriteFontFileLoader = new DirectWriteFontFileLoader();
m_directWriteFactory->RegisterFontFileLoader(m_directWriteFontFileLoader);
}
}
~CustomFontFileLoader()
{
if (m_directWriteFactory != nullptr && m_directWriteFontFileLoader != nullptr)
m_directWriteFactory->UnregisterFontFileLoader(m_directWriteFontFileLoader);
if (m_directWriteFactory != nullptr)
m_directWriteFactory->Release();
}
void addKey(const void *key, const QByteArray &fontData)
{
if (m_directWriteFontFileLoader != nullptr)
m_directWriteFontFileLoader->addKey(key, fontData);
}
void removeKey(const void *key)
{
if (m_directWriteFontFileLoader != nullptr)
m_directWriteFontFileLoader->removeKey(key);
}
IDWriteFontFileLoader *loader() const
{
return m_directWriteFontFileLoader;
}
private:
IDWriteFactory *m_directWriteFactory = nullptr;
DirectWriteFontFileLoader *m_directWriteFontFileLoader = nullptr;
};
} // Anonymous namespace } // Anonymous namespace
class QCustomFontFileLoader
{
public:
QCustomFontFileLoader(IDWriteFactory *factory)
{
m_directWriteFactory = factory;
if (m_directWriteFactory) {
m_directWriteFactory->AddRef();
m_directWriteFontFileLoader = new DirectWriteFontFileLoader();
m_directWriteFactory->RegisterFontFileLoader(m_directWriteFontFileLoader);
}
}
~QCustomFontFileLoader()
{
clear();
if (m_directWriteFactory != nullptr && m_directWriteFontFileLoader != nullptr)
m_directWriteFactory->UnregisterFontFileLoader(m_directWriteFontFileLoader);
if (m_directWriteFactory != nullptr)
m_directWriteFactory->Release();
}
void addKey(const QByteArray &fontData)
{
if (m_directWriteFontFileLoader != nullptr)
m_directWriteFontFileLoader->addKey(fontData);
}
void removeKey(const void *key)
{
if (m_directWriteFontFileLoader != nullptr)
m_directWriteFontFileLoader->removeKey(key);
}
IDWriteFontFileLoader *loader() const
{
return m_directWriteFontFileLoader;
}
void clear()
{
if (m_directWriteFontFileLoader != nullptr)
m_directWriteFontFileLoader->clear();
}
private:
IDWriteFactory *m_directWriteFactory = nullptr;
DirectWriteFontFileLoader *m_directWriteFontFileLoader = nullptr;
};
#endif // directwrite && direct2d #endif // directwrite && direct2d
@ -550,8 +565,12 @@ void QWindowsFontDatabaseBase::createDirectWriteFactory(IDWriteFactory **factory
IUnknown *result = nullptr; IUnknown *result = nullptr;
# if QT_CONFIG(directwrite3) # if QT_CONFIG(directwrite3)
DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory3), &result); DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory5), &result);
if (result == nullptr)
DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory3), &result);
# endif # endif
if (result == nullptr) if (result == nullptr)
DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory2), &result); DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory2), &result);
@ -700,28 +719,47 @@ QFont QWindowsFontDatabaseBase::systemDefaultFont()
return systemFont; return systemFont;
} }
#if QT_CONFIG(directwrite) && QT_CONFIG(direct2d) void QWindowsFontDatabaseBase::invalidate()
IDWriteFontFace *QWindowsFontDatabaseBase::createDirectWriteFace(const QByteArray &fontData) const
{ {
#if QT_CONFIG(directwrite)
m_fontFileLoader.reset(nullptr);
#endif
}
#if QT_CONFIG(directwrite) && QT_CONFIG(direct2d)
IDWriteFontFace *QWindowsFontDatabaseBase::createDirectWriteFace(const QByteArray &fontData)
{
QList<IDWriteFontFace *> faces = createDirectWriteFaces(fontData, false);
Q_ASSERT(faces.size() <= 1);
return faces.isEmpty() ? nullptr : faces.first();
}
QList<IDWriteFontFace *> QWindowsFontDatabaseBase::createDirectWriteFaces(const QByteArray &fontData,
bool queryVariations) const
{
QList<IDWriteFontFace *> ret;
QSharedPointer<QWindowsFontEngineData> fontEngineData = data(); QSharedPointer<QWindowsFontEngineData> fontEngineData = data();
if (fontEngineData->directWriteFactory == nullptr) { if (fontEngineData->directWriteFactory == nullptr) {
qCWarning(lcQpaFonts) << "DirectWrite factory not created in QWindowsFontDatabaseBase::createDirectWriteFace()"; qCWarning(lcQpaFonts) << "DirectWrite factory not created in QWindowsFontDatabaseBase::createDirectWriteFace()";
return nullptr; return ret;
} }
CustomFontFileLoader fontFileLoader(fontEngineData->directWriteFactory); if (m_fontFileLoader == nullptr)
fontFileLoader.addKey(this, fontData); m_fontFileLoader.reset(new QCustomFontFileLoader(fontEngineData->directWriteFactory));
m_fontFileLoader->addKey(fontData);
IDWriteFontFile *fontFile = nullptr; IDWriteFontFile *fontFile = nullptr;
const void *key = this; const void *key = fontData.data();
HRESULT hres = fontEngineData->directWriteFactory->CreateCustomFontFileReference(&key, HRESULT hres = fontEngineData->directWriteFactory->CreateCustomFontFileReference(&key,
sizeof(void *), sizeof(void *),
fontFileLoader.loader(), m_fontFileLoader->loader(),
&fontFile); &fontFile);
if (FAILED(hres)) { if (FAILED(hres)) {
qErrnoWarning(hres, "%s: CreateCustomFontFileReference failed", __FUNCTION__); qErrnoWarning(hres, "%s: CreateCustomFontFileReference failed", __FUNCTION__);
return nullptr; return ret;
} }
BOOL isSupportedFontType; BOOL isSupportedFontType;
@ -731,25 +769,65 @@ IDWriteFontFace *QWindowsFontDatabaseBase::createDirectWriteFace(const QByteArra
fontFile->Analyze(&isSupportedFontType, &fontFileType, &fontFaceType, &numberOfFaces); fontFile->Analyze(&isSupportedFontType, &fontFileType, &fontFaceType, &numberOfFaces);
if (!isSupportedFontType) { if (!isSupportedFontType) {
fontFile->Release(); fontFile->Release();
return nullptr; return ret;
} }
#if QT_CONFIG(directwrite3)
IDWriteFactory5 *factory5 = nullptr;
if (queryVariations && SUCCEEDED(fontEngineData->directWriteFactory->QueryInterface(__uuidof(IDWriteFactory5),
reinterpret_cast<void **>(&factory5)))) {
IDWriteFontSetBuilder1 *builder;
if (SUCCEEDED(factory5->CreateFontSetBuilder(&builder))) {
if (SUCCEEDED(builder->AddFontFile(fontFile))) {
IDWriteFontSet *fontSet;
if (SUCCEEDED(builder->CreateFontSet(&fontSet))) {
int count = fontSet->GetFontCount();
qCDebug(lcQpaFonts) << "Found" << count << "variations in font file";
for (int i = 0; i < count; ++i) {
IDWriteFontFaceReference *ref;
if (SUCCEEDED(fontSet->GetFontFaceReference(i, &ref))) {
IDWriteFontFace3 *face;
if (SUCCEEDED(ref->CreateFontFace(&face))) {
ret.append(face);
}
ref->Release();
}
}
fontSet->Release();
}
}
builder->Release();
}
factory5->Release();
}
#else
Q_UNUSED(queryVariations);
#endif
// ### Currently no support for .ttc, but we could easily return a list here. // ### Currently no support for .ttc, but we could easily return a list here.
IDWriteFontFace *directWriteFontFace = nullptr; if (ret.isEmpty()) {
hres = fontEngineData->directWriteFactory->CreateFontFace(fontFaceType, IDWriteFontFace *directWriteFontFace = nullptr;
1, hres = fontEngineData->directWriteFactory->CreateFontFace(fontFaceType,
&fontFile, 1,
0, &fontFile,
DWRITE_FONT_SIMULATIONS_NONE, 0,
&directWriteFontFace); DWRITE_FONT_SIMULATIONS_NONE,
if (FAILED(hres)) { &directWriteFontFace);
qErrnoWarning(hres, "%s: CreateFontFace failed", __FUNCTION__); if (FAILED(hres)) {
fontFile->Release(); qErrnoWarning(hres, "%s: CreateFontFace failed", __FUNCTION__);
return nullptr; fontFile->Release();
return ret;
} else {
ret.append(directWriteFontFace);
}
} }
fontFile->Release(); fontFile->Release();
return directWriteFontFace;
return ret;
} }
#endif // directwrite && direct2d #endif // directwrite && direct2d
@ -769,7 +847,10 @@ QFontEngine *QWindowsFontDatabaseBase::fontEngine(const QByteArray &fontData, qr
if (fontEngineData->directWriteFactory == nullptr) if (fontEngineData->directWriteFactory == nullptr)
return nullptr; return nullptr;
IDWriteFontFace *directWriteFontFace = createDirectWriteFace(fontData); IDWriteFontFace * directWriteFontFace = createDirectWriteFace(fontData);
if (directWriteFontFace == nullptr)
return nullptr;
fontEngine = new QWindowsFontEngineDirectWrite(directWriteFontFace, fontEngine = new QWindowsFontEngineDirectWrite(directWriteFontFace,
pixelSize, pixelSize,
fontEngineData); fontEngineData);

View File

@ -46,10 +46,13 @@
#include <QtCore/quuid.h> #include <QtCore/quuid.h>
#include <QtCore/private/qsystemlibrary_p.h> #include <QtCore/private/qsystemlibrary_p.h>
#include <QtCore/private/qwinregistry_p.h> #include <QtCore/private/qwinregistry_p.h>
#include <QtCore/private/qfactorycacheregistration_p.h> #if QT_CONFIG(cpp_winrt)
# include <QtCore/private/qfactorycacheregistration_p.h>
#endif
#include <QtCore/private/qsystemerror_p.h> #include <QtCore/private/qsystemerror_p.h>
#include <QtGui/private/qwindowsguieventdispatcher_p.h> #include <QtGui/private/qwindowsguieventdispatcher_p.h>
#include <QtGui/private/qwindowsthemecache_p.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
@ -58,6 +61,8 @@
#include <wtsapi32.h> #include <wtsapi32.h>
#include <shellscalingapi.h> #include <shellscalingapi.h>
#include "vxkex.h"
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals; using namespace Qt::StringLiterals;
@ -276,6 +281,8 @@ QWindowsContext::~QWindowsContext()
if (d->m_powerDummyWindow) if (d->m_powerDummyWindow)
DestroyWindow(d->m_powerDummyWindow); DestroyWindow(d->m_powerDummyWindow);
d->m_screenManager.destroyWindow();
unregisterWindowClasses(); unregisterWindowClasses();
if (d->m_oleInitializeResult == S_OK || d->m_oleInitializeResult == S_FALSE) { if (d->m_oleInitializeResult == S_OK || d->m_oleInitializeResult == S_FALSE) {
#ifdef QT_USE_FACTORY_CACHE_REGISTRATION #ifdef QT_USE_FACTORY_CACHE_REGISTRATION
@ -445,11 +452,25 @@ void QWindowsContext::setDetectAltGrModifier(bool a)
return QtWindows::DpiAwareness::System; return QtWindows::DpiAwareness::System;
if (QWindowsContext::user32dll.areDpiAwarenessContextsEqual(context, DPI_AWARENESS_CONTEXT_UNAWARE)) if (QWindowsContext::user32dll.areDpiAwarenessContextsEqual(context, DPI_AWARENESS_CONTEXT_UNAWARE))
return QtWindows::DpiAwareness::Unaware; return QtWindows::DpiAwareness::Unaware;
}
return QtWindows::DpiAwareness::Invalid; 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::Unaware; // Windows 7 return QtWindows::DpiAwareness::Invalid;
} }
QtWindows::DpiAwareness QWindowsContext::windowDpiAwareness(HWND hwnd) QtWindows::DpiAwareness QWindowsContext::windowDpiAwareness(HWND hwnd)
@ -457,31 +478,26 @@ QtWindows::DpiAwareness QWindowsContext::windowDpiAwareness(HWND hwnd)
if (!hwnd) if (!hwnd)
return QtWindows::DpiAwareness::Invalid; return QtWindows::DpiAwareness::Invalid;
if (QWindowsContext::user32dll.getWindowDpiAwarenessContext) const auto context = QWindowsContext::user32dll.getWindowDpiAwarenessContext ?
{ QWindowsContext::user32dll.getWindowDpiAwarenessContext(hwnd) :
const auto context = QWindowsContext::user32dll.getWindowDpiAwarenessContext(hwnd); vxkex::GetWindowDpiAwarenessContext(hwnd);
return dpiAwarenessContextToQtDpiAwareness(context);
}
return dpiAwarenessContextToQtDpiAwareness(DPI_AWARENESS_CONTEXT_UNAWARE); return dpiAwarenessContextToQtDpiAwareness(context);
} }
QtWindows::DpiAwareness QWindowsContext::processDpiAwareness() QtWindows::DpiAwareness QWindowsContext::processDpiAwareness()
{ {
if (QWindowsContext::user32dll.getThreadDpiAwarenessContext) // Although we have GetDpiAwarenessContextForProcess(), however,
{ // it's only available on Win10 1903+, which is a little higher
// Although we have GetDpiAwarenessContextForProcess(), however, // than Qt's minimum supported version (1809), so we can't use it.
// it's only available on Win10 1903+, which is a little higher // Luckily, MS docs said GetThreadDpiAwarenessContext() will also
// than Qt's minimum supported version (1809), so we can't use it. // return the default DPI_AWARENESS_CONTEXT for the process if
// Luckily, MS docs said GetThreadDpiAwarenessContext() will also // SetThreadDpiAwarenessContext() was never called. So we can use
// return the default DPI_AWARENESS_CONTEXT for the process if // it as an equivalent.
// SetThreadDpiAwarenessContext() was never called. So we can use const DPI_AWARENESS_CONTEXT context = QWindowsContext::user32dll.getThreadDpiAwarenessContext ?
// it as an equivalent. QWindowsContext::user32dll.getThreadDpiAwarenessContext() :
const auto context = QWindowsContext::user32dll.getThreadDpiAwarenessContext(); vxkex::GetThreadDpiAwarenessContext();
return dpiAwarenessContextToQtDpiAwareness(context); return dpiAwarenessContextToQtDpiAwareness(context);
}
return dpiAwarenessContextToQtDpiAwareness(DPI_AWARENESS_CONTEXT_UNAWARE);
} }
[[nodiscard]] static inline DPI_AWARENESS_CONTEXT [[nodiscard]] static inline DPI_AWARENESS_CONTEXT
@ -541,28 +557,32 @@ bool QWindowsContext::setProcessDpiAwareness(QtWindows::DpiAwareness dpiAwarenes
return true; return true;
const auto context = qtDpiAwarenessToDpiAwarenessContext(dpiAwareness); const auto context = qtDpiAwarenessToDpiAwarenessContext(dpiAwareness);
if (QWindowsContext::user32dll.isValidDpiAwarenessContext && QWindowsContext::user32dll.setProcessDpiAwarenessContext) BOOL bResultIsValid = QWindowsContext::user32dll.isValidDpiAwarenessContext ?
{ QWindowsContext::user32dll.isValidDpiAwarenessContext(context) :
if (!QWindowsContext::user32dll.isValidDpiAwarenessContext(context)) { vxkex::IsValidDpiAwarenessContext(context);
qCWarning(lcQpaWindow) << dpiAwareness << "is not supported by current system.";
return false; if (!bResultIsValid) {
} qCWarning(lcQpaWindow) << dpiAwareness << "is not supported by current system.";
if (!QWindowsContext::user32dll.setProcessDpiAwarenessContext(context)) { return false;
qCWarning(lcQpaWindow).noquote().nospace()
<< "SetProcessDpiAwarenessContext() failed: "
<< QSystemError::windowsString()
<< "\nQt's default DPI awareness context is "
<< "DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2. If you know what you "
<< "are doing, you can overwrite this default using qt.conf "
<< "(https://doc.qt.io/qt-6/highdpi.html#configuring-windows).";
return false;
}
QWindowsContextPrivate::m_v2DpiAware
= processDpiAwareness() == QtWindows::DpiAwareness::PerMonitorVersion2;
return true;
} }
return false; // Windows 7 BOOL bResultSet = QWindowsContext::user32dll.setProcessDpiAwarenessContext ?
QWindowsContext::user32dll.setProcessDpiAwarenessContext(context) :
vxkex::SetProcessDpiAwarenessContext(context);
if (!bResultSet) {
qCWarning(lcQpaWindow).noquote().nospace()
<< "SetProcessDpiAwarenessContext() failed: "
<< QSystemError::windowsString()
<< "\nQt's default DPI awareness context is "
<< "DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2. If you know what you "
<< "are doing, you can overwrite this default using qt.conf "
<< "(https://doc.qt.io/qt-6/highdpi.html#configuring-windows).";
return false;
}
QWindowsContextPrivate::m_v2DpiAware
= processDpiAwareness() == QtWindows::DpiAwareness::PerMonitorVersion2;
return true;
} }
bool QWindowsContext::isDarkMode() bool QWindowsContext::isDarkMode()
@ -585,9 +605,9 @@ bool QWindowsContext::useRTLExtensions() const
return d->m_keyMapper.useRTLExtensions(); return d->m_keyMapper.useRTLExtensions();
} }
QList<int> QWindowsContext::possibleKeys(const QKeyEvent *e) const QPlatformKeyMapper *QWindowsContext::keyMapper() const
{ {
return d->m_keyMapper.possibleKeys(e); return &d->m_keyMapper;
} }
QWindowsContext::HandleBaseWindowHash &QWindowsContext::windows() QWindowsContext::HandleBaseWindowHash &QWindowsContext::windows()
@ -994,7 +1014,7 @@ bool QWindowsContext::systemParametersInfo(unsigned action, unsigned param, void
{ {
const BOOL result = (QWindowsContext::user32dll.systemParametersInfoForDpi != nullptr && dpi != 0) const BOOL result = (QWindowsContext::user32dll.systemParametersInfoForDpi != nullptr && dpi != 0)
? QWindowsContext::user32dll.systemParametersInfoForDpi(action, param, out, 0, dpi) ? QWindowsContext::user32dll.systemParametersInfoForDpi(action, param, out, 0, dpi)
: SystemParametersInfo(action, param, out, 0); : vxkex::SystemParametersInfoForDpi(action, param, out, 0, dpi);
return result == TRUE; return result == TRUE;
} }
@ -1080,8 +1100,11 @@ static inline bool isInputMessage(UINT m)
static bool enableNonClientDpiScaling(HWND hwnd) static bool enableNonClientDpiScaling(HWND hwnd)
{ {
bool result = false; bool result = false;
if (QWindowsContext::user32dll.enableNonClientDpiScaling && QWindowsContext::windowDpiAwareness(hwnd) == QtWindows::DpiAwareness::PerMonitor) { if (QWindowsContext::windowDpiAwareness(hwnd) == QtWindows::DpiAwareness::PerMonitor) {
result = QWindowsContext::user32dll.enableNonClientDpiScaling(hwnd) != FALSE; result = QWindowsContext::user32dll.enableNonClientDpiScaling ?
(QWindowsContext::user32dll.enableNonClientDpiScaling(hwnd) != FALSE) :
(vxkex::EnableNonClientDpiScaling(hwnd) != FALSE);
if (!result) { if (!result) {
const DWORD errorCode = GetLastError(); const DWORD errorCode = GetLastError();
qErrnoWarning(int(errorCode), "EnableNonClientDpiScaling() failed for HWND %p (%lu)", qErrnoWarning(int(errorCode), "EnableNonClientDpiScaling() failed for HWND %p (%lu)",
@ -1267,7 +1290,7 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
if (wParam == DBT_DEVNODES_CHANGED) if (wParam == DBT_DEVNODES_CHANGED)
initTouch(); initTouch();
break; break;
case QtWindows::KeyboardLayoutChangeEvent: case QtWindows::InputLanguageChangeEvent:
if (QWindowsInputContext *wic = windowsInputContext()) if (QWindowsInputContext *wic = windowsInputContext())
wic->handleInputLanguageChanged(wParam, lParam); wic->handleInputLanguageChanged(wParam, lParam);
Q_FALLTHROUGH(); Q_FALLTHROUGH();
@ -1379,6 +1402,7 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
QWindowSystemInterface::handleCloseEvent(platformWindow->window()); QWindowSystemInterface::handleCloseEvent(platformWindow->window());
return true; return true;
case QtWindows::ThemeChanged: { case QtWindows::ThemeChanged: {
QWindowsThemeCache::clearThemeCache(platformWindow->handle());
// Switch from Aero to Classic changes margins. // Switch from Aero to Classic changes margins.
if (QWindowsTheme *theme = QWindowsTheme::instance()) if (QWindowsTheme *theme = QWindowsTheme::instance())
theme->windowsThemeChanged(platformWindow->window()); theme->windowsThemeChanged(platformWindow->window());
@ -1517,7 +1541,7 @@ void QWindowsContext::handleFocusEvent(QtWindows::WindowsEventType et,
} }
if (nextActiveWindow != d->m_lastActiveWindow) { if (nextActiveWindow != d->m_lastActiveWindow) {
d->m_lastActiveWindow = nextActiveWindow; d->m_lastActiveWindow = nextActiveWindow;
QWindowSystemInterface::handleWindowActivated(nextActiveWindow, Qt::ActiveWindowFocusReason); QWindowSystemInterface::handleFocusWindowChanged(nextActiveWindow, Qt::ActiveWindowFocusReason);
} }
} }
@ -1547,7 +1571,7 @@ bool QWindowsContext::handleContextMenuEvent(QWindow *window, const MSG &msg)
} }
QWindowSystemInterface::handleContextMenuEvent(window, mouseTriggered, pos, globalPos, QWindowSystemInterface::handleContextMenuEvent(window, mouseTriggered, pos, globalPos,
QWindowsKeyMapper::queryKeyboardModifiers()); keyMapper()->queryKeyboardModifiers());
return true; return true;
} }
#endif #endif
@ -1568,7 +1592,7 @@ void QWindowsContext::handleExitSizeMove(QWindow *window)
const Qt::MouseButtons appButtons = QGuiApplication::mouseButtons(); const Qt::MouseButtons appButtons = QGuiApplication::mouseButtons();
if (currentButtons == appButtons) if (currentButtons == appButtons)
return; return;
const Qt::KeyboardModifiers keyboardModifiers = QWindowsKeyMapper::queryKeyboardModifiers(); const Qt::KeyboardModifiers keyboardModifiers = keyMapper()->queryKeyboardModifiers();
const QPoint globalPos = QWindowsCursor::mousePosition(); const QPoint globalPos = QWindowsCursor::mousePosition();
const QPlatformWindow *platWin = window->handle(); const QPlatformWindow *platWin = window->handle();
const QPoint localPos = platWin->mapFromGlobal(globalPos); const QPoint localPos = platWin->mapFromGlobal(globalPos);

View File

@ -34,6 +34,7 @@ Q_DECLARE_LOGGING_CATEGORY(lcQpaScreen)
class QWindow; class QWindow;
class QPlatformScreen; class QPlatformScreen;
class QPlatformWindow; class QPlatformWindow;
class QPlatformKeyMapper;
class QWindowsMenuBar; class QWindowsMenuBar;
class QWindowsScreenManager; class QWindowsScreenManager;
class QWindowsTabletSupport; class QWindowsTabletSupport;
@ -217,7 +218,7 @@ public:
unsigned systemInfo() const; unsigned systemInfo() const;
bool useRTLExtensions() const; bool useRTLExtensions() const;
QList<int> possibleKeys(const QKeyEvent *e) const; QPlatformKeyMapper *keyMapper() const;
HandleBaseWindowHash &windows(); HandleBaseWindowHash &windows();

View File

@ -28,9 +28,13 @@
#include <QtCore/qdebug.h> #include <QtCore/qdebug.h>
#include <QtCore/qbuffer.h> #include <QtCore/qbuffer.h>
#include <QtCore/qpoint.h> #include <QtCore/qpoint.h>
#include <QtCore/qpointer.h>
#include <QtCore/private/qcomobject_p.h>
#include <shlobj.h> #include <shlobj.h>
#include "vxkex.h"
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
/*! /*!
@ -167,7 +171,7 @@ static Qt::MouseButtons lastButtons = Qt::NoButton;
\internal \internal
*/ */
class QWindowsOleDropSource : public QWindowsComBase<IDropSource> class QWindowsOleDropSource : public QComObject<IDropSource>
{ {
public: public:
enum Mode { enum Mode {
@ -526,7 +530,8 @@ QWindowsOleDropTarget::DragLeave()
qCDebug(lcQpaMime) << __FUNCTION__ << ' ' << m_window; qCDebug(lcQpaMime) << __FUNCTION__ << ' ' << m_window;
lastModifiers = QWindowsKeyMapper::queryKeyboardModifiers(); const auto *keyMapper = QWindowsContext::instance()->keyMapper();
lastModifiers = keyMapper->queryKeyboardModifiers();
lastButtons = QWindowsMouseHandler::queryMouseButtons(); lastButtons = QWindowsMouseHandler::queryMouseButtons();
QWindowSystemInterface::handleDrag(m_window, nullptr, QPoint(), Qt::IgnoreAction, QWindowSystemInterface::handleDrag(m_window, nullptr, QPoint(), Qt::IgnoreAction,
@ -611,7 +616,6 @@ QWindowsOleDropTarget::Drop(LPDATAOBJECT pDataObj, DWORD grfKeyState,
*/ */
bool QWindowsDrag::m_canceled = false; bool QWindowsDrag::m_canceled = false;
bool QWindowsDrag::m_dragging = false;
QWindowsDrag::QWindowsDrag() = default; QWindowsDrag::QWindowsDrag() = default;
@ -671,7 +675,11 @@ static HRESULT startDoDragDrop(LPDATAOBJECT pDataObj, LPDROPSOURCE pDropSource,
const quint32 pointerId = GET_POINTERID_WPARAM(msg.wParam); const quint32 pointerId = GET_POINTERID_WPARAM(msg.wParam);
POINTER_INFO pointerInfo{}; POINTER_INFO pointerInfo{};
if (!QWindowsContext::user32dll.getPointerInfo || !QWindowsContext::user32dll.getPointerInfo(pointerId, &pointerInfo)) BOOL bResultPointerInfo = QWindowsContext::user32dll.getPointerInfo ?
QWindowsContext::user32dll.getPointerInfo(pointerId, &pointerInfo) :
vxkex::GetPointerInfo(pointerId, &pointerInfo);
if (!bResultPointerInfo)
return E_FAIL; return E_FAIL;
if (pointerInfo.pointerFlags & POINTER_FLAG_PRIMARY) { if (pointerInfo.pointerFlags & POINTER_FLAG_PRIMARY) {
@ -739,10 +747,7 @@ Qt::DropAction QWindowsDrag::drag(QDrag *drag)
const DWORD allowedEffects = translateToWinDragEffects(possibleActions); const DWORD allowedEffects = translateToWinDragEffects(possibleActions);
qCDebug(lcQpaMime) << '>' << __FUNCTION__ << "possible Actions=0x" qCDebug(lcQpaMime) << '>' << __FUNCTION__ << "possible Actions=0x"
<< Qt::hex << int(possibleActions) << "effects=0x" << allowedEffects << Qt::dec; << Qt::hex << int(possibleActions) << "effects=0x" << allowedEffects << Qt::dec;
// Indicate message handlers we are in DoDragDrop() event loop.
QWindowsDrag::m_dragging = true;
const HRESULT r = startDoDragDrop(dropDataObject, windowDropSource, allowedEffects, &resultEffect); const HRESULT r = startDoDragDrop(dropDataObject, windowDropSource, allowedEffects, &resultEffect);
QWindowsDrag::m_dragging = false;
const DWORD reportedPerformedEffect = dropDataObject->reportedPerformedEffect(); const DWORD reportedPerformedEffect = dropDataObject->reportedPerformedEffect();
if (r == DRAGDROP_S_DROP) { if (r == DRAGDROP_S_DROP) {
if (reportedPerformedEffect == DROPEFFECT_MOVE && resultEffect != DROPEFFECT_MOVE) { if (reportedPerformedEffect == DROPEFFECT_MOVE && resultEffect != DROPEFFECT_MOVE) {

View File

@ -17,6 +17,8 @@
#include <QtCore/private/qdebug_p.h> #include <QtCore/private/qdebug_p.h>
#include <QtCore/private/qtools_p.h> #include <QtCore/private/qtools_p.h>
#include "vxkex.h"
#if defined(WM_APPCOMMAND) #if defined(WM_APPCOMMAND)
# ifndef FAPPCOMMAND_MOUSE # ifndef FAPPCOMMAND_MOUSE
# define FAPPCOMMAND_MOUSE 0x8000 # define FAPPCOMMAND_MOUSE 0x8000
@ -88,9 +90,17 @@ QWindowsKeyMapper::~QWindowsKeyMapper()= default;
#define VK_OEM_3 0xC0 #define VK_OEM_3 0xC0
#endif #endif
// We not only need the scancode itself but also the extended bit of key messages. Thus we need // Get scancode from the given message
// the additional bit when masking the scancode. static constexpr quint32 getScancode(const MSG &msg)
enum { scancodeBitmask = 0x1ff }; {
const auto keyFlags = HIWORD(msg.lParam);
quint32 scancode = LOBYTE(keyFlags);
// if extended-key flag is on, the scan code consists of a sequence of two bytes,
// where the first byte has a value of 0xe0.
if ((keyFlags & KF_EXTENDED) != 0)
scancode |= 0xE000;
return scancode;
}
// Key recorder ------------------------------------------------------------------------[ start ] -- // Key recorder ------------------------------------------------------------------------[ start ] --
struct KeyRecord { struct KeyRecord {
@ -532,33 +542,6 @@ QDebug operator<<(QDebug d, const KeyboardLayoutItem &k)
d << ')'; d << ')';
return d; return d;
} }
// Helpers to format a list of int as Qt key sequence
class formatKeys
{
public:
explicit formatKeys(const QList<int> &keys) : m_keys(keys) {}
private:
friend QDebug operator<<(QDebug d, const formatKeys &keys);
const QList<int> &m_keys;
};
QDebug operator<<(QDebug d, const formatKeys &k)
{
QDebugStateSaver saver(d);
d.nospace();
d << '(';
for (int i =0, size = k.m_keys.size(); i < size; ++i) {
if (i)
d << ", ";
d << QKeySequence(k.m_keys.at(i));
}
d << ')';
return d;
}
#else // !QT_NO_DEBUG_STREAM
static int formatKeys(const QList<int> &) { return 0; }
#endif // QT_NO_DEBUG_STREAM #endif // QT_NO_DEBUG_STREAM
/** /**
@ -656,7 +639,7 @@ void QWindowsKeyMapper::updateKeyMap(const MSG &msg)
{ {
unsigned char kbdBuffer[256]; // Will hold the complete keyboard state unsigned char kbdBuffer[256]; // Will hold the complete keyboard state
GetKeyboardState(kbdBuffer); GetKeyboardState(kbdBuffer);
const quint32 scancode = (msg.lParam >> 16) & scancodeBitmask; const quint32 scancode = getScancode(msg);
updatePossibleKeyCodes(kbdBuffer, scancode, quint32(msg.wParam)); updatePossibleKeyCodes(kbdBuffer, scancode, quint32(msg.wParam));
} }
@ -751,28 +734,18 @@ static inline QString messageKeyText(const MSG &msg)
[[nodiscard]] static inline int getTitleBarHeight(const HWND hwnd) [[nodiscard]] static inline int getTitleBarHeight(const HWND hwnd)
{ {
if (QWindowsContext::user32dll.getDpiForWindow && QWindowsContext::user32dll.getSystemMetricsForDpi) const BOOL bNewAPI = (QWindowsContext::user32dll.getSystemMetricsForDpi != nullptr);
{ const UINT dpi = bNewAPI ? QWindowsContext::user32dll.getDpiForWindow(hwnd) : vxkex::GetDpiForWindow(hwnd);
const UINT dpi = QWindowsContext::user32dll.getDpiForWindow(hwnd); const int captionHeight = bNewAPI ? QWindowsContext::user32dll.getSystemMetricsForDpi(SM_CYCAPTION, dpi) : vxkex::GetSystemMetricsForDpi(SM_CYCAPTION, dpi);
const int captionHeight = QWindowsContext::user32dll.getSystemMetricsForDpi(SM_CYCAPTION, dpi); if (IsZoomed(hwnd))
if (IsZoomed(hwnd)) return captionHeight;
return captionHeight; // The frame height should also be taken into account if the window
// The frame height should also be taken into account if the window // is not maximized.
// is not maximized. const int frameHeight = bNewAPI ?
const int frameHeight = QWindowsContext::user32dll.getSystemMetricsForDpi(SM_CYSIZEFRAME, dpi) (QWindowsContext::user32dll.getSystemMetricsForDpi(SM_CYSIZEFRAME, dpi) + QWindowsContext::user32dll.getSystemMetricsForDpi(SM_CXPADDEDBORDER, dpi))
+ QWindowsContext::user32dll.getSystemMetricsForDpi(SM_CXPADDEDBORDER, dpi); : (vxkex::GetSystemMetricsForDpi(SM_CYSIZEFRAME, dpi) + vxkex::GetSystemMetricsForDpi(SM_CXPADDEDBORDER, dpi));
return captionHeight + frameHeight;
} return captionHeight + frameHeight;
else
{
const int captionHeight = GetSystemMetrics(SM_CYCAPTION);
if (IsZoomed(hwnd))
return captionHeight;
// The frame height should also be taken into account if the window
// is not maximized.
const int frameHeight = GetSystemMetrics(SM_CYSIZEFRAME) + GetSystemMetrics(SM_CXPADDEDBORDER);
return captionHeight + frameHeight;
}
} }
[[nodiscard]] static inline bool isSystemMenuOffsetNeeded(const Qt::WindowFlags flags) [[nodiscard]] static inline bool isSystemMenuOffsetNeeded(const Qt::WindowFlags flags)
@ -955,7 +928,7 @@ bool QWindowsKeyMapper::translateKeyEventInternal(QWindow *window, MSG msg,
m_seenAltGr = true; m_seenAltGr = true;
const UINT msgType = msg.message; const UINT msgType = msg.message;
const quint32 scancode = (msg.lParam >> 16) & scancodeBitmask; const quint32 scancode = getScancode(msg);
auto vk_key = quint32(msg.wParam); auto vk_key = quint32(msg.wParam);
quint32 nModifiers = 0; quint32 nModifiers = 0;
@ -1352,7 +1325,7 @@ bool QWindowsKeyMapper::translateKeyEventInternal(QWindow *window, MSG msg,
return result; return result;
} }
Qt::KeyboardModifiers QWindowsKeyMapper::queryKeyboardModifiers() Qt::KeyboardModifiers QWindowsKeyMapper::queryKeyboardModifiers() const
{ {
Qt::KeyboardModifiers modifiers = Qt::NoModifier; Qt::KeyboardModifiers modifiers = Qt::NoModifier;
if (GetKeyState(VK_SHIFT) < 0) if (GetKeyState(VK_SHIFT) < 0)
@ -1366,9 +1339,9 @@ Qt::KeyboardModifiers QWindowsKeyMapper::queryKeyboardModifiers()
return modifiers; return modifiers;
} }
QList<int> QWindowsKeyMapper::possibleKeys(const QKeyEvent *e) const QList<QKeyCombination> QWindowsKeyMapper::possibleKeyCombinations(const QKeyEvent *e) const
{ {
QList<int> result; QList<QKeyCombination> result;
const quint32 nativeVirtualKey = e->nativeVirtualKey(); const quint32 nativeVirtualKey = e->nativeVirtualKey();
@ -1382,31 +1355,34 @@ QList<int> QWindowsKeyMapper::possibleKeys(const QKeyEvent *e) const
quint32 baseKey = kbItem.qtKey[0]; quint32 baseKey = kbItem.qtKey[0];
Qt::KeyboardModifiers keyMods = e->modifiers(); Qt::KeyboardModifiers keyMods = e->modifiers();
if (baseKey == Qt::Key_Return && (e->nativeModifiers() & ExtendedKey)) { if (baseKey == Qt::Key_Return && (e->nativeModifiers() & ExtendedKey)) {
result << (Qt::Key_Enter | keyMods).toCombined(); result << (Qt::Key_Enter | keyMods);
return result; return result;
} }
result << int(baseKey) + int(keyMods); // The base key is _always_ valid, of course
// The base key is _always_ valid, of course
result << QKeyCombination::fromCombined(int(baseKey) + int(keyMods));
for (size_t i = 1; i < NumMods; ++i) { for (size_t i = 1; i < NumMods; ++i) {
Qt::KeyboardModifiers neededMods = ModsTbl[i]; Qt::KeyboardModifiers neededMods = ModsTbl[i];
quint32 key = kbItem.qtKey[i]; quint32 key = kbItem.qtKey[i];
if (key && key != baseKey && ((keyMods & neededMods) == neededMods)) { if (key && key != baseKey && ((keyMods & neededMods) == neededMods)) {
const Qt::KeyboardModifiers missingMods = keyMods & ~neededMods; const Qt::KeyboardModifiers missingMods = keyMods & ~neededMods;
const int matchedKey = int(key) + int(missingMods); const auto matchedKey = QKeyCombination::fromCombined(int(key) + int(missingMods));
const auto it = const auto it = std::find_if(result.begin(), result.end(),
std::find_if(result.begin(), result.end(), [key](auto keyCombination) {
[key] (int k) { return (k & ~Qt::KeyboardModifierMask) == key; }); return keyCombination.key() == key;
});
// QTBUG-67200: Use the match with the least modifiers (prefer // QTBUG-67200: Use the match with the least modifiers (prefer
// Shift+9 over Alt + Shift + 9) resulting in more missing modifiers. // Shift+9 over Alt + Shift + 9) resulting in more missing modifiers.
if (it == result.end()) if (it == result.end())
result << matchedKey; result << matchedKey;
else if (missingMods > Qt::KeyboardModifiers(*it & Qt::KeyboardModifierMask)) else if (missingMods > it->keyboardModifiers())
*it = matchedKey; *it = matchedKey;
} }
} }
qCDebug(lcQpaEvents) << __FUNCTION__ << e << "nativeVirtualKey=" qCDebug(lcQpaEvents) << __FUNCTION__ << e << "nativeVirtualKey="
<< Qt::showbase << Qt::hex << e->nativeVirtualKey() << Qt::dec << Qt::noshowbase << Qt::showbase << Qt::hex << e->nativeVirtualKey() << Qt::dec << Qt::noshowbase
<< e->modifiers() << kbItem << "\n returns" << formatKeys(result); << e->modifiers() << kbItem << "\n returns" << result;
return result; return result;
} }

View File

@ -27,6 +27,8 @@
#include <windowsx.h> #include <windowsx.h>
#include "vxkex.h"
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
enum { enum {
@ -48,7 +50,11 @@ bool QWindowsPointerHandler::translatePointerEvent(QWindow *window, HWND hwnd, Q
*result = 0; *result = 0;
const quint32 pointerId = GET_POINTERID_WPARAM(msg.wParam); const quint32 pointerId = GET_POINTERID_WPARAM(msg.wParam);
if (!QWindowsContext::user32dll.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(); qWarning() << "GetPointerType() failed:" << qt_error_string();
return false; return false;
} }
@ -62,12 +68,21 @@ bool QWindowsPointerHandler::translatePointerEvent(QWindow *window, HWND hwnd, Q
} }
case QT_PT_TOUCH: { case QT_PT_TOUCH: {
quint32 pointerCount = 0; quint32 pointerCount = 0;
if (!QWindowsContext::user32dll.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(); qWarning() << "GetPointerFrameTouchInfo() failed:" << qt_error_string();
return false; return false;
} }
QVarLengthArray<POINTER_TOUCH_INFO, 10> touchInfo(pointerCount); QVarLengthArray<POINTER_TOUCH_INFO, 10> touchInfo(pointerCount);
if (!QWindowsContext::user32dll.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(); qWarning() << "GetPointerFrameTouchInfo() failed:" << qt_error_string();
return false; return false;
} }
@ -80,10 +95,12 @@ bool QWindowsPointerHandler::translatePointerEvent(QWindow *window, HWND hwnd, Q
// dispatch any skipped frames if event compression is disabled by the app // dispatch any skipped frames if event compression is disabled by the app
if (historyCount > 1 && !QCoreApplication::testAttribute(Qt::AA_CompressHighFrequencyEvents)) { if (historyCount > 1 && !QCoreApplication::testAttribute(Qt::AA_CompressHighFrequencyEvents)) {
touchInfo.resize(pointerCount * historyCount); touchInfo.resize(pointerCount * historyCount);
if (!QWindowsContext::user32dll.getPointerFrameTouchInfoHistory(pointerId,
&historyCount, BOOL bResultTouchHistory = QWindowsContext::user32dll.getPointerFrameTouchInfoHistory ?
&pointerCount, QWindowsContext::user32dll.getPointerFrameTouchInfoHistory(pointerId, &historyCount, &pointerCount, touchInfo.data()) :
touchInfo.data())) { vxkex::GetPointerFrameTouchInfoHistory(pointerId, &historyCount, &pointerCount, touchInfo.data());
if (!bResultTouchHistory) {
qWarning() << "GetPointerFrameTouchInfoHistory() failed:" << qt_error_string(); qWarning() << "GetPointerFrameTouchInfoHistory() failed:" << qt_error_string();
return false; return false;
} }
@ -101,7 +118,11 @@ bool QWindowsPointerHandler::translatePointerEvent(QWindow *window, HWND hwnd, Q
} }
case QT_PT_PEN: { case QT_PT_PEN: {
POINTER_PEN_INFO penInfo; POINTER_PEN_INFO penInfo;
if (!QWindowsContext::user32dll.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(); qWarning() << "GetPointerPenInfo() failed:" << qt_error_string();
return false; return false;
} }
@ -113,7 +134,11 @@ bool QWindowsPointerHandler::translatePointerEvent(QWindow *window, HWND hwnd, Q
|| !QCoreApplication::testAttribute(Qt::AA_CompressTabletEvents))) { || !QCoreApplication::testAttribute(Qt::AA_CompressTabletEvents))) {
QVarLengthArray<POINTER_PEN_INFO, 10> penInfoHistory(historyCount); QVarLengthArray<POINTER_PEN_INFO, 10> penInfoHistory(historyCount);
if (!QWindowsContext::user32dll.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(); qWarning() << "GetPointerPenInfoHistory() failed:" << qt_error_string();
return false; return false;
} }
@ -428,8 +453,9 @@ bool QWindowsPointerHandler::translateTouchEvent(QWindow *window, HWND hwnd,
return false; return false;
if (msg.message == WM_POINTERCAPTURECHANGED) { if (msg.message == WM_POINTERCAPTURECHANGED) {
const auto *keyMapper = QWindowsContext::instance()->keyMapper();
QWindowSystemInterface::handleTouchCancelEvent(window, m_touchDevice.data(), QWindowSystemInterface::handleTouchCancelEvent(window, m_touchDevice.data(),
QWindowsKeyMapper::queryKeyboardModifiers()); keyMapper->queryKeyboardModifiers());
m_lastTouchPoints.clear(); m_lastTouchPoints.clear();
return true; return true;
} }
@ -519,7 +545,10 @@ bool QWindowsPointerHandler::translateTouchEvent(QWindow *window, HWND hwnd,
inputIds.insert(touchPoint.id); inputIds.insert(touchPoint.id);
// Avoid getting repeated messages for this frame if there are multiple pointerIds // Avoid getting repeated messages for this frame if there are multiple pointerIds
QWindowsContext::user32dll.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 // Some devices send touches for each finger in a different message/frame, instead of consolidating
@ -539,8 +568,9 @@ bool QWindowsPointerHandler::translateTouchEvent(QWindow *window, HWND hwnd,
if (allStates == QEventPoint::State::Released) if (allStates == QEventPoint::State::Released)
m_touchInputIDToTouchPointID.clear(); m_touchInputIDToTouchPointID.clear();
const auto *keyMapper = QWindowsContext::instance()->keyMapper();
QWindowSystemInterface::handleTouchEvent(window, m_touchDevice.data(), touchPoints, QWindowSystemInterface::handleTouchEvent(window, m_touchDevice.data(), touchPoints,
QWindowsKeyMapper::queryKeyboardModifiers()); keyMapper->queryKeyboardModifiers());
return false; // Allow mouse messages to be generated. return false; // Allow mouse messages to be generated.
} }
@ -565,7 +595,12 @@ bool QWindowsPointerHandler::translatePenEvent(QWindow *window, HWND hwnd, QtWin
auto *penInfo = static_cast<POINTER_PEN_INFO *>(vPenInfo); auto *penInfo = static_cast<POINTER_PEN_INFO *>(vPenInfo);
RECT pRect, dRect; RECT pRect, dRect;
if (!QWindowsContext::user32dll.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; return false;
const auto systemId = (qint64)penInfo->pointerInfo.sourceDevice; const auto systemId = (qint64)penInfo->pointerInfo.sourceDevice;
@ -673,7 +708,8 @@ bool QWindowsPointerHandler::translatePenEvent(QWindow *window, HWND hwnd, QtWin
wumPlatformWindow->applyCursor(); wumPlatformWindow->applyCursor();
} }
} }
const Qt::KeyboardModifiers keyModifiers = QWindowsKeyMapper::queryKeyboardModifiers(); const auto *keyMapper = QWindowsContext::instance()->keyMapper();
const Qt::KeyboardModifiers keyModifiers = keyMapper->queryKeyboardModifiers();
QWindowSystemInterface::handleTabletEvent(target, device.data(), QWindowSystemInterface::handleTabletEvent(target, device.data(),
localPos, hiResGlobalPos, mouseButtons, localPos, hiResGlobalPos, mouseButtons,
@ -762,7 +798,8 @@ bool QWindowsPointerHandler::translateMouseEvent(QWindow *window,
: QWindowsGeometryHint::mapFromGlobal(targetHwnd, globalPos); : QWindowsGeometryHint::mapFromGlobal(targetHwnd, globalPos);
} }
const Qt::KeyboardModifiers keyModifiers = QWindowsKeyMapper::queryKeyboardModifiers(); const auto *keyMapper = QWindowsContext::instance()->keyMapper();
const Qt::KeyboardModifiers keyModifiers = keyMapper->queryKeyboardModifiers();
QWindow *currentWindowUnderPointer = getWindowUnderPointer(window, globalPos); QWindow *currentWindowUnderPointer = getWindowUnderPointer(window, globalPos);
if (et == QtWindows::MouseWheelEvent) if (et == QtWindows::MouseWheelEvent)

View File

@ -32,6 +32,8 @@
#include <setupapi.h> #include <setupapi.h>
#include <shellscalingapi.h> #include <shellscalingapi.h>
#include "vxkex.h"
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals; using namespace Qt::StringLiterals;
@ -43,12 +45,18 @@ static inline QDpi deviceDPI(HDC hdc)
static inline QDpi monitorDPI(HMONITOR hMonitor) static inline QDpi monitorDPI(HMONITOR hMonitor)
{ {
if (QWindowsContext::shcoredll.isValid()) { UINT dpiX;
UINT dpiX; UINT dpiY;
UINT dpiY;
if (SUCCEEDED(QWindowsContext::shcoredll.getDpiForMonitor(hMonitor, MDT_EFFECTIVE_DPI, &dpiX, &dpiY))) HRESULT hr = S_OK;
return QDpi(dpiX, dpiY);
} 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}; return {0, 0};
} }
@ -579,51 +587,58 @@ QRect QWindowsScreen::virtualGeometry(const QPlatformScreen *screen) // cf QScre
bool QWindowsScreen::setOrientationPreference(Qt::ScreenOrientation o) bool QWindowsScreen::setOrientationPreference(Qt::ScreenOrientation o)
{ {
bool result = false; bool result = false;
if (QWindowsContext::user32dll.setDisplayAutoRotationPreferences) { ORIENTATION_PREFERENCE orientationPreference = ORIENTATION_PREFERENCE_NONE;
ORIENTATION_PREFERENCE orientationPreference = ORIENTATION_PREFERENCE_NONE; switch (o) {
switch (o) { case Qt::PrimaryOrientation:
case Qt::PrimaryOrientation: break;
break; case Qt::PortraitOrientation:
case Qt::PortraitOrientation: orientationPreference = ORIENTATION_PREFERENCE_PORTRAIT;
orientationPreference = ORIENTATION_PREFERENCE_PORTRAIT; break;
break; case Qt::LandscapeOrientation:
case Qt::LandscapeOrientation: orientationPreference = ORIENTATION_PREFERENCE_LANDSCAPE;
orientationPreference = ORIENTATION_PREFERENCE_LANDSCAPE; break;
break; case Qt::InvertedPortraitOrientation:
case Qt::InvertedPortraitOrientation: orientationPreference = ORIENTATION_PREFERENCE_PORTRAIT_FLIPPED;
orientationPreference = ORIENTATION_PREFERENCE_PORTRAIT_FLIPPED; break;
break; case Qt::InvertedLandscapeOrientation:
case Qt::InvertedLandscapeOrientation: orientationPreference = ORIENTATION_PREFERENCE_LANDSCAPE_FLIPPED;
orientationPreference = ORIENTATION_PREFERENCE_LANDSCAPE_FLIPPED; break;
break;
}
result = QWindowsContext::user32dll.setDisplayAutoRotationPreferences(orientationPreference);
} }
if (QWindowsContext::user32dll.setDisplayAutoRotationPreferences)
result = QWindowsContext::user32dll.setDisplayAutoRotationPreferences(orientationPreference);
else
result = vxkex::SetDisplayAutoRotationPreferences(orientationPreference);
return result; return result;
} }
Qt::ScreenOrientation QWindowsScreen::orientationPreference() Qt::ScreenOrientation QWindowsScreen::orientationPreference()
{ {
Qt::ScreenOrientation result = Qt::PrimaryOrientation; Qt::ScreenOrientation result = Qt::PrimaryOrientation;
if (QWindowsContext::user32dll.getDisplayAutoRotationPreferences) { ORIENTATION_PREFERENCE orientationPreference = ORIENTATION_PREFERENCE_NONE;
DWORD orientationPreference = ORIENTATION_PREFERENCE_NONE;
if (QWindowsContext::user32dll.getDisplayAutoRotationPreferences(&orientationPreference)) { BOOL bResult = TRUE;
switch (orientationPreference) {
case ORIENTATION_PREFERENCE_NONE: if (QWindowsContext::user32dll.getDisplayAutoRotationPreferences)
break; bResult = QWindowsContext::user32dll.getDisplayAutoRotationPreferences((DWORD *)&orientationPreference);
case ORIENTATION_PREFERENCE_LANDSCAPE: else
result = Qt::LandscapeOrientation; bResult = vxkex::GetDisplayAutoRotationPreferences(&orientationPreference);
break;
case ORIENTATION_PREFERENCE_PORTRAIT: if (bResult) {
result = Qt::PortraitOrientation; switch (orientationPreference) {
break; case ORIENTATION_PREFERENCE_NONE:
case ORIENTATION_PREFERENCE_LANDSCAPE_FLIPPED: break;
result = Qt::InvertedLandscapeOrientation; case ORIENTATION_PREFERENCE_LANDSCAPE:
break; result = Qt::LandscapeOrientation;
case ORIENTATION_PREFERENCE_PORTRAIT_FLIPPED: break;
result = Qt::InvertedPortraitOrientation; case ORIENTATION_PREFERENCE_PORTRAIT:
break; result = Qt::PortraitOrientation;
} break;
case ORIENTATION_PREFERENCE_LANDSCAPE_FLIPPED:
result = Qt::InvertedLandscapeOrientation;
break;
case ORIENTATION_PREFERENCE_PORTRAIT_FLIPPED:
result = Qt::InvertedPortraitOrientation;
break;
} }
} }
return result; return result;
@ -704,11 +719,15 @@ void QWindowsScreenManager::initialize()
handleScreenChanges(); handleScreenChanges();
} }
QWindowsScreenManager::~QWindowsScreenManager() void QWindowsScreenManager::destroyWindow()
{ {
qCDebug(lcQpaScreen) << "Destroying display change observer" << m_displayChangeObserver;
DestroyWindow(m_displayChangeObserver); DestroyWindow(m_displayChangeObserver);
m_displayChangeObserver = nullptr;
} }
QWindowsScreenManager::~QWindowsScreenManager() = default;
bool QWindowsScreenManager::isSingleScreen() bool QWindowsScreenManager::isSingleScreen()
{ {
return QWindowsContext::instance()->screenManager().screens().size() < 2; return QWindowsContext::instance()->screenManager().screens().size() < 2;

View File

@ -7,6 +7,7 @@
#include "qwindowsmenu.h" #include "qwindowsmenu.h"
#include "qwindowsdialoghelpers.h" #include "qwindowsdialoghelpers.h"
#include "qwindowscontext.h" #include "qwindowscontext.h"
#include "qwindowsiconengine.h"
#include "qwindowsintegration.h" #include "qwindowsintegration.h"
#if QT_CONFIG(systemtrayicon) #if QT_CONFIG(systemtrayicon)
# include "qwindowssystemtrayicon.h" # include "qwindowssystemtrayicon.h"
@ -27,6 +28,7 @@
#include <QtCore/qthread.h> #include <QtCore/qthread.h>
#include <QtCore/qmutex.h> #include <QtCore/qmutex.h>
#include <QtCore/qwaitcondition.h> #include <QtCore/qwaitcondition.h>
#include <QtCore/qoperatingsystemversion.h>
#include <QtGui/qcolor.h> #include <QtGui/qcolor.h>
#include <QtGui/qpalette.h> #include <QtGui/qpalette.h>
#include <QtGui/qguiapplication.h> #include <QtGui/qguiapplication.h>
@ -42,7 +44,7 @@
#include <algorithm> #include <algorithm>
#include <VersionHelpers.h> #include "vxkex.h"
#if QT_CONFIG(cpp_winrt) #if QT_CONFIG(cpp_winrt)
# include <QtCore/private/qt_winrtbase_p.h> # include <QtCore/private/qt_winrtbase_p.h>
@ -81,11 +83,11 @@ static inline QColor mixColors(const QColor &c1, const QColor &c2)
(c1.blue() + c2.blue()) / 2}; (c1.blue() + c2.blue()) / 2};
} }
static inline QColor getSysColor(int index) enum AccentColorLevel {
{ AccentColorDarkest,
COLORREF cr = GetSysColor(index); AccentColorNormal,
return QColor(GetRValue(cr), GetGValue(cr), GetBValue(cr)); AccentColorLightest
} };
#if QT_CONFIG(cpp_winrt) #if QT_CONFIG(cpp_winrt)
static constexpr QColor getSysColor(winrt::Windows::UI::Color &&color) static constexpr QColor getSysColor(winrt::Windows::UI::Color &&color)
@ -94,6 +96,54 @@ static constexpr QColor getSysColor(winrt::Windows::UI::Color &&color)
} }
#endif #endif
[[maybe_unused]] [[nodiscard]] static inline QColor qt_accentColor(AccentColorLevel level)
{
QColor accent;
QColor accentLight;
QColor accentDarkest;
#if QT_CONFIG(cpp_winrt)
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));
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<DWORD>(value));
if (!abgr.isValid())
return {};
accent = QColor::fromRgb(abgr.blue(), abgr.green(), abgr.red(), abgr.alpha());
accentLight = accent.lighter(120);
accentDarkest = accent.darker(120 * 120 * 120);
}
if (level == AccentColorDarkest)
return accentDarkest;
else if (level == AccentColorLightest)
return accentLight;
return accent;
}
static inline QColor getSysColor(int index)
{
COLORREF cr = GetSysColor(index);
return QColor(GetRValue(cr), GetGValue(cr), GetBValue(cr));
}
// QTBUG-48823/Windows 10: SHGetFileInfo() (as called by item views on file system // 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 // models has been observed to trigger a WM_PAINT on the mainwindow. Suppress the
// behavior by running it in a thread. // behavior by running it in a thread.
@ -223,44 +273,17 @@ static QColor placeHolderColor(QColor textColor)
return textColor; return textColor;
} }
[[maybe_unused]] [[nodiscard]] static inline QColor qt_accentColor()
{
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<DWORD>(value));
if (!abgr.isValid())
return {};
return QColor::fromRgb(abgr.blue(), abgr.green(), abgr.red(), abgr.alpha());
}
/* /*
This is used when the theme is light mode, and when the theme is dark but the This is used when the theme is light mode, and when the theme is dark but the
application doesn't support dark mode. In the latter case, we need to check. application doesn't support dark mode. In the latter case, we need to check.
*/ */
static void populateLightSystemBasePalette(QPalette &result) static void populateLightSystemBasePalette(QPalette &result)
{ {
QColor background = getSysColor(COLOR_BTNFACE); const QColor background = getSysColor(COLOR_BTNFACE);
QColor textColor = getSysColor(COLOR_WINDOWTEXT); const QColor textColor = getSysColor(COLOR_WINDOWTEXT);
QColor accent = qt_accentColor();
QColor accentDarkest = accent.darker(120 * 120 * 120);
#if QT_CONFIG(cpp_winrt) const QColor accent = qt_accentColor(AccentColorNormal);
if (IsWindows10OrGreater()) const QColor accentDarkest = qt_accentColor(AccentColorDarkest);
{
// respect the Windows 11 accent color
using namespace winrt::Windows::UI::ViewManagement;
const auto settings = UISettings();
accent = getSysColor(settings.GetColorValue(UIColorType::Accent));
accentDarkest = getSysColor(settings.GetColorValue(UIColorType::AccentDark3));
}
#endif
const QColor linkColor = accent; const QColor linkColor = accent;
const QColor btnFace = background; const QColor btnFace = background;
@ -298,7 +321,7 @@ static void populateDarkSystemBasePalette(QPalette &result)
{ {
QColor foreground = Qt::white; QColor foreground = Qt::white;
QColor background = QColor(0x1E, 0x1E, 0x1E); QColor background = QColor(0x1E, 0x1E, 0x1E);
QColor accent = qt_accentColor(); QColor accent = qt_accentColor(AccentColorNormal);
QColor accentDark = accent.darker(120); QColor accentDark = accent.darker(120);
QColor accentDarker = accentDark.darker(120); QColor accentDarker = accentDark.darker(120);
QColor accentDarkest = accentDarker.darker(120); QColor accentDarkest = accentDarker.darker(120);
@ -307,7 +330,7 @@ static void populateDarkSystemBasePalette(QPalette &result)
QColor accentLightest = accentLighter.lighter(120); QColor accentLightest = accentLighter.lighter(120);
#if QT_CONFIG(cpp_winrt) #if QT_CONFIG(cpp_winrt)
if (IsWindows10OrGreater()) if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows10)
{ {
using namespace winrt::Windows::UI::ViewManagement; using namespace winrt::Windows::UI::ViewManagement;
const auto settings = UISettings(); const auto settings = UISettings();
@ -472,7 +495,10 @@ static inline QStringList iconThemeSearchPaths()
static inline QStringList styleNames() static inline QStringList styleNames()
{ {
return { QStringLiteral("WindowsVista"), QStringLiteral("Windows") }; QStringList styles = { QStringLiteral("WindowsVista"), QStringLiteral("Windows") };
if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows11)
styles.prepend(QStringLiteral("Windows11"));
return styles;
} }
static inline int uiEffects() static inline int uiEffects()
@ -537,6 +563,8 @@ QVariant QWindowsTheme::themeHint(ThemeHint hint) const
Qt::ColorScheme QWindowsTheme::colorScheme() const Qt::ColorScheme QWindowsTheme::colorScheme() const
{ {
if (queryHighContrast())
return Qt::ColorScheme::Unknown;
return QWindowsContext::isDarkMode() ? Qt::ColorScheme::Dark : Qt::ColorScheme::Light; return QWindowsContext::isDarkMode() ? Qt::ColorScheme::Dark : Qt::ColorScheme::Light;
} }
@ -559,24 +587,10 @@ void QWindowsTheme::refreshPalettes()
m_palettes[MenuPalette] = new QPalette(menuPalette(*m_palettes[SystemPalette], light)); m_palettes[MenuPalette] = new QPalette(menuPalette(*m_palettes[SystemPalette], light));
m_palettes[MenuBarPalette] = menuBarPalette(*m_palettes[MenuPalette], light); m_palettes[MenuBarPalette] = menuBarPalette(*m_palettes[MenuPalette], light);
if (!light) { if (!light) {
QColor accent = qt_accentColor();
QColor accentLight = accent.lighter(120);
QColor accentDarkest = accent.darker(120 * 120 * 120);
#if QT_CONFIG(cpp_winrt)
if (IsWindows10OrGreater())
{
using namespace winrt::Windows::UI::ViewManagement;
const auto settings = UISettings();
accent = getSysColor(settings.GetColorValue(UIColorType::Accent));
accentLight = getSysColor(settings.GetColorValue(UIColorType::AccentLight1));
accentDarkest = getSysColor(settings.GetColorValue(UIColorType::AccentDark3));
}
#endif
m_palettes[CheckBoxPalette] = new QPalette(*m_palettes[SystemPalette]); m_palettes[CheckBoxPalette] = new QPalette(*m_palettes[SystemPalette]);
m_palettes[CheckBoxPalette]->setColor(QPalette::Active, QPalette::Base, accent); m_palettes[CheckBoxPalette]->setColor(QPalette::Active, QPalette::Base, qt_accentColor(AccentColorNormal));
m_palettes[CheckBoxPalette]->setColor(QPalette::Active, QPalette::Button, accentLight); m_palettes[CheckBoxPalette]->setColor(QPalette::Active, QPalette::Button, qt_accentColor(AccentColorLightest));
m_palettes[CheckBoxPalette]->setColor(QPalette::Inactive, QPalette::Base, accentDarkest); m_palettes[CheckBoxPalette]->setColor(QPalette::Inactive, QPalette::Base, qt_accentColor(AccentColorDarkest));
m_palettes[RadioButtonPalette] = new QPalette(*m_palettes[CheckBoxPalette]); m_palettes[RadioButtonPalette] = new QPalette(*m_palettes[CheckBoxPalette]);
} }
} }
@ -586,15 +600,15 @@ QPalette QWindowsTheme::systemPalette(Qt::ColorScheme colorScheme)
QPalette result = standardPalette(); QPalette result = standardPalette();
switch (colorScheme) { switch (colorScheme) {
case Qt::ColorScheme::Light: case Qt::ColorScheme::Light:
populateLightSystemBasePalette(result); populateLightSystemBasePalette(result);
break; break;
case Qt::ColorScheme::Dark: case Qt::ColorScheme::Dark:
populateDarkSystemBasePalette(result); populateDarkSystemBasePalette(result);
break; break;
default: default:
qFatal("Unknown color scheme"); qFatal("Unknown color scheme");
break; break;
} }
if (result.window() != result.base()) { if (result.window() != result.base()) {
@ -675,14 +689,11 @@ void QWindowsTheme::refreshFonts()
fixedFont.setStyleHint(QFont::TypeWriter); fixedFont.setStyleHint(QFont::TypeWriter);
LOGFONT lfIconTitleFont; LOGFONT lfIconTitleFont;
QFont iconTitleFont; if (QWindowsContext::user32dll.systemParametersInfoForDpi)
if (QWindowsContext::user32dll.systemParametersInfoForDpi) {
QWindowsContext::user32dll.systemParametersInfoForDpi(SPI_GETICONTITLELOGFONT, sizeof(lfIconTitleFont), &lfIconTitleFont, 0, dpi); QWindowsContext::user32dll.systemParametersInfoForDpi(SPI_GETICONTITLELOGFONT, sizeof(lfIconTitleFont), &lfIconTitleFont, 0, dpi);
iconTitleFont = QWindowsFontDatabase::LOGFONT_to_QFont(lfIconTitleFont, dpi); else
} else { vxkex::SystemParametersInfoForDpi(SPI_GETICONTITLELOGFONT, sizeof(lfIconTitleFont), &lfIconTitleFont, 0, dpi);
SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(lfIconTitleFont), &lfIconTitleFont, 0); const QFont iconTitleFont = QWindowsFontDatabase::LOGFONT_to_QFont(lfIconTitleFont, dpi);
iconTitleFont = QWindowsFontDatabase::LOGFONT_to_QFont(lfIconTitleFont);
}
m_fonts[SystemFont] = new QFont(QWindowsFontDatabase::systemDefaultFont()); m_fonts[SystemFont] = new QFont(QWindowsFontDatabase::systemDefaultFont());
m_fonts[MenuFont] = new QFont(menuFont); m_fonts[MenuFont] = new QFont(menuFont);
@ -856,15 +867,18 @@ QPixmap QWindowsTheme::standardPixmap(StandardPixmap sp, const QSizeF &pixmapSiz
} }
if (stockId != SIID_INVALID) { if (stockId != SIID_INVALID) {
QPixmap pixmap;
SHSTOCKICONINFO iconInfo; SHSTOCKICONINFO iconInfo;
memset(&iconInfo, 0, sizeof(iconInfo)); memset(&iconInfo, 0, sizeof(iconInfo));
iconInfo.cbSize = sizeof(iconInfo); iconInfo.cbSize = sizeof(iconInfo);
stockFlags |= (pixmapSize.width() > 16 ? SHGFI_LARGEICON : SHGFI_SMALLICON); stockFlags |= SHGSI_ICONLOCATION;
if (SHGetStockIconInfo(stockId, SHGFI_ICON | stockFlags, &iconInfo) == S_OK) { if (SHGetStockIconInfo(stockId, stockFlags, &iconInfo) == S_OK) {
pixmap = qt_pixmapFromWinHICON(iconInfo.hIcon); const auto iconSize = pixmapSize.width();
DestroyIcon(iconInfo.hIcon); HICON icon;
return pixmap; if (SHDefExtractIcon(iconInfo.szPath, iconInfo.iIcon, 0, &icon, nullptr, iconSize) == S_OK) {
QPixmap pixmap = qt_pixmapFromWinHICON(icon);
DestroyIcon(icon);
return pixmap;
}
} }
} }
@ -1088,6 +1102,11 @@ QIcon QWindowsTheme::fileIcon(const QFileInfo &fileInfo, QPlatformTheme::IconOpt
return QIcon(new QWindowsFileIconEngine(fileInfo, iconOptions)); return QIcon(new QWindowsFileIconEngine(fileInfo, iconOptions));
} }
QIconEngine *QWindowsTheme::createIconEngine(const QString &iconName) const
{
return new QWindowsIconEngine(iconName);
}
static inline bool doUseNativeMenus() static inline bool doUseNativeMenus()
{ {
const unsigned options = QWindowsIntegration::instance()->options(); const unsigned options = QWindowsIntegration::instance()->options();

View File

@ -27,6 +27,7 @@
#include <QtGui/qwindow.h> #include <QtGui/qwindow.h>
#include <QtGui/qregion.h> #include <QtGui/qregion.h>
#include <QtGui/qopenglcontext.h> #include <QtGui/qopenglcontext.h>
#include <QtGui/private/qwindowsthemecache_p.h>
#include <private/qwindow_p.h> // QWINDOWSIZE_MAX #include <private/qwindow_p.h> // QWINDOWSIZE_MAX
#include <private/qguiapplication_p.h> #include <private/qguiapplication_p.h>
#include <private/qhighdpiscaling_p.h> #include <private/qhighdpiscaling_p.h>
@ -43,6 +44,8 @@
#include <shellscalingapi.h> #include <shellscalingapi.h>
#include "vxkex.h"
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
using QWindowCreationContextPtr = QSharedPointer<QWindowCreationContext>; using QWindowCreationContextPtr = QSharedPointer<QWindowCreationContext>;
@ -526,8 +529,8 @@ static inline void updateGLWindowSettings(const QWindow *w, HWND hwnd, Qt::Windo
return QWindowsContext::user32dll.getSystemMetricsForDpi(SM_CXSIZEFRAME, dpi) return QWindowsContext::user32dll.getSystemMetricsForDpi(SM_CXSIZEFRAME, dpi)
+ QWindowsContext::user32dll.getSystemMetricsForDpi(SM_CXPADDEDBORDER, dpi); + QWindowsContext::user32dll.getSystemMetricsForDpi(SM_CXPADDEDBORDER, dpi);
} }
else
return GetSystemMetrics(SM_CXSIZEFRAME) + GetSystemMetrics(SM_CXPADDEDBORDER); return vxkex::GetSystemMetricsForDpi(SM_CXSIZEFRAME, dpi) + vxkex::GetSystemMetricsForDpi(SM_CXPADDEDBORDER, dpi);
} }
/*! /*!
@ -537,16 +540,22 @@ static inline void updateGLWindowSettings(const QWindow *w, HWND hwnd, Qt::Windo
static QMargins invisibleMargins(QPoint screenPoint) static QMargins invisibleMargins(QPoint screenPoint)
{ {
if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows10) { POINT pt = {screenPoint.x(), screenPoint.y()};
POINT pt = {screenPoint.x(), screenPoint.y()}; if (HMONITOR hMonitor = MonitorFromPoint(pt, MONITOR_DEFAULTTONULL)) {
if (HMONITOR hMonitor = MonitorFromPoint(pt, MONITOR_DEFAULTTONULL)) { if (QWindowsContext::shcoredll.isValid()) {
if (QWindowsContext::shcoredll.isValid()) { UINT dpiX;
UINT dpiX; UINT dpiY;
UINT dpiY;
if (SUCCEEDED(QWindowsContext::shcoredll.getDpiForMonitor(hMonitor, MDT_EFFECTIVE_DPI, &dpiX, &dpiY))) { HRESULT hr = S_OK;
const int gap = getResizeBorderThickness(dpiX);
return QMargins(gap, 0, gap, gap); 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);
} }
} }
} }
@ -555,12 +564,10 @@ static QMargins invisibleMargins(QPoint screenPoint)
[[nodiscard]] static inline QMargins invisibleMargins(const HWND hwnd) [[nodiscard]] static inline QMargins invisibleMargins(const HWND hwnd)
{ {
if (QWindowsContext::user32dll.getDpiForWindow) { const UINT dpi = (QWindowsContext::user32dll.getDpiForWindow) ? QWindowsContext::user32dll.getDpiForWindow(hwnd) : vxkex::GetDpiForWindow(hwnd);
const UINT dpi = QWindowsContext::user32dll.getDpiForWindow(hwnd);
const int gap = getResizeBorderThickness(dpi); const int gap = getResizeBorderThickness(dpi);
return QMargins(gap, 0, gap, gap); return QMargins(gap, 0, gap, gap);
}
return QMargins();
} }
/*! /*!
@ -848,6 +855,10 @@ void WindowCreationData::fromWindow(const QWindow *w, const Qt::WindowFlags flag
// NOTE: WS_EX_TRANSPARENT flag can make mouse inputs fall through a layered window // NOTE: WS_EX_TRANSPARENT flag can make mouse inputs fall through a layered window
if (flagsIn & Qt::WindowTransparentForInput) if (flagsIn & Qt::WindowTransparentForInput)
exStyle |= WS_EX_LAYERED | WS_EX_TRANSPARENT; exStyle |= WS_EX_LAYERED | WS_EX_TRANSPARENT;
// Currently only compatible with D3D surfaces, use it with care.
if (qEnvironmentVariableIntValue("QT_QPA_DISABLE_REDIRECTION_SURFACE"))
exStyle |= WS_EX_NOREDIRECTIONBITMAP;
} }
} }
@ -1074,10 +1085,17 @@ QMargins QWindowsGeometryHint::frame(const QWindow *w, DWORD style, DWORD exStyl
return {}; return {};
RECT rect = {0,0,0,0}; RECT rect = {0,0,0,0};
style &= ~DWORD(WS_OVERLAPPED); // Not permitted, see docs. style &= ~DWORD(WS_OVERLAPPED); // Not permitted, see docs.
if (QWindowsContext::user32dll.adjustWindowRectExForDpi && if (QWindowsContext::user32dll.adjustWindowRectExForDpi)
QWindowsContext::user32dll.adjustWindowRectExForDpi(&rect, style, FALSE, exStyle, unsigned(qRound(dpi))) == FALSE) { {
qErrnoWarning("%s: AdjustWindowRectExForDpi failed", __FUNCTION__); 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), const QMargins result(qAbs(rect.left), qAbs(rect.top),
qAbs(rect.right), qAbs(rect.bottom)); qAbs(rect.right), qAbs(rect.bottom));
qCDebug(lcQpaWindow).nospace() << __FUNCTION__ << " style=" qCDebug(lcQpaWindow).nospace() << __FUNCTION__ << " style="
@ -1364,6 +1382,8 @@ QWindowsForeignWindow::QWindowsForeignWindow(QWindow *window, HWND hwnd)
, m_hwnd(hwnd) , m_hwnd(hwnd)
, m_topLevelStyle(0) , m_topLevelStyle(0)
{ {
if (QPlatformWindow::parent())
setParent(QPlatformWindow::parent());
} }
void QWindowsForeignWindow::setParent(const QPlatformWindow *newParentWindow) void QWindowsForeignWindow::setParent(const QPlatformWindow *newParentWindow)
@ -1539,6 +1559,7 @@ QWindowsWindow::QWindowsWindow(QWindow *aWindow, const QWindowsWindowData &data)
QWindowsWindow::~QWindowsWindow() QWindowsWindow::~QWindowsWindow()
{ {
setFlag(WithinDestroy); setFlag(WithinDestroy);
QWindowsThemeCache::clearThemeCache(m_data.hwnd);
if (testFlag(TouchRegistered)) if (testFlag(TouchRegistered))
UnregisterTouchWindow(m_data.hwnd); UnregisterTouchWindow(m_data.hwnd);
destroyWindow(); destroyWindow();
@ -1568,7 +1589,7 @@ void QWindowsWindow::initialize()
} }
} }
QWindowsWindow::setSavedDpi(QWindowsContext::user32dll.getDpiForWindow ? QWindowsWindow::setSavedDpi(QWindowsContext::user32dll.getDpiForWindow ?
QWindowsContext::user32dll.getDpiForWindow(handle()) : 96); QWindowsContext::user32dll.getDpiForWindow(handle()) : vxkex::GetDpiForWindow(handle()));
} }
QSurfaceFormat QWindowsWindow::format() const QSurfaceFormat QWindowsWindow::format() const
@ -2018,6 +2039,9 @@ void QWindowsWindow::handleDpiChanged(HWND hwnd, WPARAM wParam, LPARAM lParam)
const UINT dpi = HIWORD(wParam); const UINT dpi = HIWORD(wParam);
const qreal scale = dpiRelativeScale(dpi); const qreal scale = dpiRelativeScale(dpi);
setSavedDpi(dpi); setSavedDpi(dpi);
QWindowsThemeCache::clearThemeCache(hwnd);
// Send screen change first, so that the new screen is set during any following resize // Send screen change first, so that the new screen is set during any following resize
checkForScreenChanged(QWindowsWindow::FromDpiChange); checkForScreenChanged(QWindowsWindow::FromDpiChange);
@ -2060,20 +2084,17 @@ void QWindowsWindow::handleDpiChanged(HWND hwnd, WPARAM wParam, LPARAM lParam)
void QWindowsWindow::handleDpiChangedAfterParent(HWND hwnd) void QWindowsWindow::handleDpiChangedAfterParent(HWND hwnd)
{ {
if (QWindowsContext::user32dll.getDpiForWindow) const UINT dpi = QWindowsContext::user32dll.getDpiForWindow ? QWindowsContext::user32dll.getDpiForWindow(hwnd) : vxkex::GetDpiForWindow(hwnd);
{ const qreal scale = dpiRelativeScale(dpi);
const UINT dpi = QWindowsContext::user32dll.getDpiForWindow(hwnd); setSavedDpi(dpi);
const qreal scale = dpiRelativeScale(dpi);
setSavedDpi(dpi);
checkForScreenChanged(QWindowsWindow::FromDpiChange); checkForScreenChanged(QWindowsWindow::FromDpiChange);
// Child windows do not get WM_GETDPISCALEDSIZE messages to inform // Child windows do not get WM_GETDPISCALEDSIZE messages to inform
// Windows about the new size, so we need to manually scale them. // Windows about the new size, so we need to manually scale them.
QRect currentGeometry = geometry(); QRect currentGeometry = geometry();
QRect scaledGeometry = QRect(currentGeometry.topLeft() * scale, currentGeometry.size() * scale); QRect scaledGeometry = QRect(currentGeometry.topLeft() * scale, currentGeometry.size() * scale);
setGeometry(scaledGeometry); setGeometry(scaledGeometry);
}
} }
static QRect normalFrameGeometry(HWND hwnd) static QRect normalFrameGeometry(HWND hwnd)
@ -2485,6 +2506,11 @@ void QWindowsWindow::handleWindowStateChange(Qt::WindowStates state)
GetWindowPlacement(m_data.hwnd, &windowPlacement); GetWindowPlacement(m_data.hwnd, &windowPlacement);
const RECT geometry = RECTfromQRect(m_data.restoreGeometry); const RECT geometry = RECTfromQRect(m_data.restoreGeometry);
windowPlacement.rcNormalPosition = geometry; windowPlacement.rcNormalPosition = geometry;
// Even if the window is hidden, windowPlacement's showCmd is not SW_HIDE, so change it
// manually to avoid unhiding a hidden window with the subsequent call to
// SetWindowPlacement().
if (!isVisible())
windowPlacement.showCmd = SW_HIDE;
SetWindowPlacement(m_data.hwnd, &windowPlacement); SetWindowPlacement(m_data.hwnd, &windowPlacement);
} }
// QTBUG-17548: We send expose events when receiving WM_Paint, but for // QTBUG-17548: We send expose events when receiving WM_Paint, but for

View File

@ -0,0 +1,430 @@
#pragma once
#include <shtypes.h>
#include <winuser.h>
#include <windef.h>
#include <shellscalingapi.h>
#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)
{
switch ((ULONG_PTR)DpiContext) {
case (ULONG_PTR)DPI_AWARENESS_CONTEXT_UNAWARE:
//NOTHING;
break;
case (ULONG_PTR)DPI_AWARENESS_CONTEXT_SYSTEM_AWARE:
case (ULONG_PTR)DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE:
case (ULONG_PTR)DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2:
SetProcessDPIAware();
break;
default:
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)
{
switch ((ULONG_PTR)Value) {
case (ULONG_PTR)DPI_AWARENESS_CONTEXT_UNAWARE:
case (ULONG_PTR)DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED:
case (ULONG_PTR)DPI_AWARENESS_CONTEXT_SYSTEM_AWARE:
case (ULONG_PTR)DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE:
case (ULONG_PTR)DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2:
return TRUE;
default:
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

File diff suppressed because it is too large Load Diff