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_Public, // PublicShareLocation
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
static const GUID folderIds_li[] = {
@ -137,6 +139,8 @@ static GUID writableSpecialFolderId(QStandardPaths::StandardLocation type)
FOLDERID_LocalAppDataLow,// AppConfigLocation ("Local" path)
FOLDERID_Public, // PublicShareLocation
FOLDERID_Templates, // TemplatesLocation
GUID(), // StateLocation
GUID(), // GenericStateLocation
};
static_assert(sizeof(folderIds_li) == sizeof(folderIds));
@ -191,6 +195,23 @@ QString QStandardPaths::writableLocation(StandardLocation type)
result = QDir::tempPath();
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:
result = sHGetKnownFolderPath(writableSpecialFolderId(type));
if (!result.isEmpty() && isConfigLocation(type)) {

View File

@ -7,7 +7,6 @@
#include "qcoreapplication.h"
#include <private/qsystemlibrary_p.h>
#include "qoperatingsystemversion.h"
#include "qpair.h"
#include "qset.h"
#include "qsocketnotifier.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 *dict = sn_vec[type];
QSockNot *sn = dict ? dict->value(wp) : 0;
QSockNot *sn = dict ? dict->value(qintptr(wp)) : 0;
if (sn == nullptr) {
d->postActivateSocketNotifiers();
} 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);
// 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)
{
Q_ASSERT(notifier);
int sockfd = notifier->socket();
qintptr sockfd = notifier->socket();
int type = notifier->type();
#ifndef QT_NO_DEBUG
if (sockfd < 0) {
@ -587,7 +586,7 @@ void QEventDispatcherWin32::registerSocketNotifier(QSocketNotifier *notifier)
const char *t[] = { "Read", "Write", "Exception" };
/* Variable "socket" below is a function pointer. */
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;
@ -631,7 +630,7 @@ void QEventDispatcherWin32::unregisterSocketNotifier(QSocketNotifier *notifier)
{
Q_ASSERT(notifier);
#ifndef QT_NO_DEBUG
int sockfd = notifier->socket();
qintptr sockfd = notifier->socket();
if (sockfd < 0) {
qWarning("QEventDispatcherWin32::unregisterSocketNotifier: invalid socket identifier");
return;
@ -648,7 +647,7 @@ void QEventDispatcherWin32::doUnregisterSocketNotifier(QSocketNotifier *notifier
{
Q_D(QEventDispatcherWin32);
int type = notifier->type();
int sockfd = notifier->socket();
qintptr sockfd = notifier->socket();
Q_ASSERT(sockfd >= 0);
QSFDict::iterator it = d->active_fd.find(sockfd);
@ -911,3 +910,5 @@ HWND QEventDispatcherWin32::internalHwnd()
}
QT_END_NAMESPACE
#include "moc_qeventdispatcher_win_p.cpp"

View File

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

View File

@ -15,15 +15,15 @@
// We mean it.
//
#include <qdeadlinetimer.h>
#include <private/qglobal_p.h>
#include <QtCore/qtsan_impl.h>
QT_BEGIN_NAMESPACE
namespace QtDummyFutex {
constexpr inline bool futexAvailable() { return false; }
template <typename Atomic>
inline bool futexWait(Atomic &, typename Atomic::Type, int = 0)
inline bool futexWait(Atomic &, typename Atomic::Type, QDeadlineTimer = {})
{ Q_UNREACHABLE_RETURN(false); }
template <typename Atomic> inline void futexWakeOne(Atomic &)
{ Q_UNREACHABLE(); }
@ -33,82 +33,16 @@ namespace QtDummyFutex {
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
# include <sys/syscall.h>
# include <errno.h>
# include <limits.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
# include "qfutex_linux_p.h"
//#elif defined(Q_OS_WIN)
//# include "qfutex_win_p.h"
#else
QT_BEGIN_NAMESPACE
namespace QtFutex = QtDummyFutex;
QT_END_NAMESPACE

View File

@ -8,7 +8,6 @@
#include "qmutex.h"
#include <qdebug.h>
#include "qatomic.h"
#include "qelapsedtimer.h"
#include "qfutex_p.h"
#include "qthread.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
{
qint64 remainingTime = deadlineTimer.remainingTimeNSecs();
if (remainingTime == 0)
if (deadlineTimer.hasExpired())
return false;
if (futexAvailable()) {
if (Q_UNLIKELY(remainingTime < 0)) { // deadlineTimer.isForever()
if (Q_UNLIKELY(deadlineTimer.isForever())) {
lockInternal();
return true;
}
@ -689,8 +687,8 @@ bool QBasicMutex::lockInternal(QDeadlineTimer deadlineTimer) QT_MUTEX_LOCK_NOEXC
if (d_ptr.fetchAndStoreAcquire(dummyFutexValue()) == nullptr)
return true;
Q_FOREVER {
if (!futexWait(d_ptr, dummyFutexValue(), remainingTime))
for (;;) {
if (!futexWait(d_ptr, dummyFutexValue(), deadlineTimer))
return false;
// 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)
return true;
// calculate the remaining time
remainingTime = deadlineTimer.remainingTimeNSecs();
if (remainingTime <= 0)
if (deadlineTimer.hasExpired())
return false;
}
}
@ -713,7 +709,7 @@ bool QBasicMutex::lockInternal(QDeadlineTimer deadlineTimer) QT_MUTEX_LOCK_NOEXC
continue;
if (copy == dummyLocked()) {
if (remainingTime == 0)
if (deadlineTimer.hasExpired())
return false;
// The mutex is locked but does not have a QMutexPrivate yet.
// 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);
if (remainingTime == 0 && !d->possiblyUnlocked.loadRelaxed())
if (deadlineTimer.hasExpired() && !d->possiblyUnlocked.loadRelaxed())
return false;
// 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());
return true;
} else {
Q_ASSERT(remainingTime >= 0);
// timed out
d->derefWaiters(1);
//There may be a race in which the mutex is unlocked right after we timed out,
@ -915,10 +910,10 @@ QT_END_NAMESPACE
#if defined(QT_ALWAYS_USE_FUTEX)
// nothing
#elif defined(Q_OS_MAC)
#elif defined(Q_OS_DARWIN)
# include "qmutex_mac.cpp"
#elif defined(Q_OS_WIN)
# include "qmutex_win.cpp"
#else
# include "qmutex_unix.cpp"
#endif
#endif

View File

@ -95,22 +95,47 @@ using namespace Qt::StringLiterals;
/*!
\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
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
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
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
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
@ -259,9 +284,7 @@ bool QRhiD3D11::create(QRhi::Flags flags)
if (!activeAdapter && (requestedAdapterIndex < 0 || requestedAdapterIndex == adapterIndex)) {
activeAdapter = adapter;
adapterLuid = desc.AdapterLuid;
driverInfoStruct.deviceName = name.toUtf8();
driverInfoStruct.deviceId = desc.DeviceId;
driverInfoStruct.vendorId = desc.VendorId;
QRhiD3D::fillDriverInfo(&driverInfoStruct, desc);
qCDebug(QRHI_LOG_INFO, " using this adapter");
} else {
adapter->Release();
@ -304,21 +327,24 @@ bool QRhiD3D11::create(QRhi::Flags flags)
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
// fail already in create() if that's not the case.
ID3D11VertexShader *testShader = nullptr;
if (SUCCEEDED(dev->CreateVertexShader(g_testVertexShader, sizeof(g_testVertexShader), nullptr, &testShader))) {
testShader->Release();
} else {
qWarning("D3D11 smoke test failed (failed to create vertex shader)");
ctx->Release();
return false;
}
const bool supports11_1 = SUCCEEDED(ctx->QueryInterface(__uuidof(ID3D11DeviceContext1), reinterpret_cast<void **>(&context)));
ctx->Release();
if (!supports11_1) {
qWarning("ID3D11DeviceContext1 not supported");
static const char *msg = "D3D11 smoke test: Failed to create vertex shader";
if (flags.testFlag(QRhi::SuppressSmokeTestWarnings))
qCDebug(QRHI_LOG_INFO, "%s", msg);
else
qWarning("%s", msg);
return false;
}
@ -328,11 +354,19 @@ bool QRhiD3D11::create(QRhi::Flags flags)
// still not support this D3D_FEATURE_LEVEL_11_1 feature. (e.g.
// because it only does 11_0)
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;
}
} 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;
}
} else {
@ -342,12 +376,14 @@ bool QRhiD3D11::create(QRhi::Flags flags)
if (SUCCEEDED(dev->QueryInterface(__uuidof(IDXGIDevice), reinterpret_cast<void **>(&dxgiDev)))) {
IDXGIAdapter *adapter = nullptr;
if (SUCCEEDED(dxgiDev->GetAdapter(&adapter))) {
DXGI_ADAPTER_DESC desc;
adapter->GetDesc(&desc);
adapterLuid = desc.AdapterLuid;
driverInfoStruct.deviceName = QString::fromUtf16(reinterpret_cast<char16_t *>(desc.Description)).toUtf8();
driverInfoStruct.deviceId = desc.DeviceId;
driverInfoStruct.vendorId = desc.VendorId;
IDXGIAdapter1 *adapter1 = nullptr;
if (SUCCEEDED(adapter->QueryInterface(__uuidof(IDXGIAdapter1), reinterpret_cast<void **>(&adapter1)))) {
DXGI_ADAPTER_DESC1 desc;
adapter1->GetDesc1(&desc);
adapterLuid = desc.AdapterLuid;
QRhiD3D::fillDriverInfo(&driverInfoStruct, desc);
adapter1->Release();
}
adapter->Release();
}
dxgiDev->Release();
@ -358,11 +394,6 @@ bool QRhiD3D11::create(QRhi::Flags flags)
if (FAILED(context->QueryInterface(__uuidof(ID3DUserDefinedAnnotation), reinterpret_cast<void **>(&annotations))))
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;
nativeHandlesStruct.dev = dev;
@ -388,7 +419,16 @@ void QRhiD3D11::destroy()
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) {
annotations->Release();
@ -592,6 +632,8 @@ bool QRhiD3D11::isFeatureSupported(QRhi::Feature feature) const
return true;
case QRhi::ThreeDimensionalTextureMipmaps:
return true;
case QRhi::MultiView:
return false;
default:
Q_UNREACHABLE();
return false;
@ -1262,7 +1304,6 @@ const QRhiNativeHandles *QRhiD3D11::nativeHandles(QRhiCommandBuffer *cb)
void QRhiD3D11::beginExternal(QRhiCommandBuffer *cb)
{
QD3D11CommandBuffer *cbD = QRHI_RES(QD3D11CommandBuffer, cb);
// no timestampSwapChain, in order to avoid timestamp mess
executeCommandBuffer(cbD);
cbD->resetCommands();
}
@ -1285,6 +1326,19 @@ double QRhiD3D11::lastCompletedGpuTime(QRhiCommandBuffer *cb)
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)
{
Q_UNUSED(flags);
@ -1301,12 +1355,22 @@ QRhi::FrameOpResult QRhiD3D11::beginFrame(QRhiSwapChain *swapChain, QRhi::BeginF
finishActiveReadbacks();
if (swapChainD->timestamps.active[currentFrameSlot]) {
if (swapChainD->timestamps.active[swapChainD->currentTimestampPairIndex]) {
double elapsedSec = 0;
if (swapChainD->timestamps.tryQueryTimestamps(currentFrameSlot, context, &elapsedSec))
if (swapChainD->timestamps.tryQueryTimestamps(swapChainD->currentTimestampPairIndex, context, &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;
}
@ -1316,17 +1380,13 @@ QRhi::FrameOpResult QRhiD3D11::endFrame(QRhiSwapChain *swapChain, QRhi::EndFrame
Q_ASSERT(contextState.currentSwapChain = swapChainD);
const int currentFrameSlot = swapChainD->currentFrameSlot;
ID3D11Query *tsDisjoint = swapChainD->timestamps.disjointQuery[currentFrameSlot];
const int tsIdx = QD3D11SwapChain::BUFFER_COUNT * currentFrameSlot;
ID3D11Query *tsStart = swapChainD->timestamps.query[tsIdx];
ID3D11Query *tsEnd = swapChainD->timestamps.query[tsIdx + 1];
const bool recordTimestamps = tsDisjoint && tsStart && tsEnd && !swapChainD->timestamps.active[currentFrameSlot];
QD3D11CommandBuffer::Command &cmd(swapChainD->cb.commands.get());
cmd.cmd = QD3D11CommandBuffer::Command::EndFrame;
cmd.args.endFrame.tsQuery = nullptr; // done later manually, see below
cmd.args.endFrame.tsDisjointQuery = nullptr;
// send all commands to the context
if (recordTimestamps)
executeCommandBuffer(&swapChainD->cb, swapChainD);
else
executeCommandBuffer(&swapChainD->cb);
executeCommandBuffer(&swapChainD->cb);
if (swapChainD->sampleDesc.Count > 1) {
context->ResolveSubresource(swapChainD->backBufferTex, 0,
@ -1334,11 +1394,15 @@ QRhi::FrameOpResult QRhiD3D11::endFrame(QRhiSwapChain *swapChain, QRhi::EndFrame
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) {
context->End(tsEnd);
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)) {
@ -1383,12 +1447,36 @@ QRhi::FrameOpResult QRhiD3D11::beginOffscreenFrame(QRhiCommandBuffer **cb, QRhi:
ofr.cbWrapper.resetState();
*cb = &ofr.cbWrapper;
if (ofr.timestamps.active[ofr.timestampIdx]) {
double elapsedSec = 0;
if (ofr.timestamps.tryQueryTimestamps(ofr.timestampIdx, context, &elapsedSec))
ofr.cbWrapper.lastGpuTime = elapsedSec;
if (rhiFlags.testFlag(QRhi::EnableTimestamps)) {
D3D11_QUERY_DESC queryDesc = {};
if (!ofr.tsDisjointQuery) {
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;
}
@ -1397,25 +1485,39 @@ QRhi::FrameOpResult QRhiD3D11::endOffscreenFrame(QRhi::EndFrameFlags flags)
Q_UNUSED(flags);
ofr.active = false;
ID3D11Query *tsDisjoint = ofr.timestamps.disjointQuery[ofr.timestampIdx];
ID3D11Query *tsStart = ofr.timestamps.query[ofr.timestampIdx * 2];
ID3D11Query *tsEnd = ofr.timestamps.query[ofr.timestampIdx * 2 + 1];
const bool recordTimestamps = tsDisjoint && tsStart && tsEnd && !ofr.timestamps.active[ofr.timestampIdx];
if (recordTimestamps) {
context->Begin(tsDisjoint);
context->End(tsStart); // record timestamp; no Begin() for D3D11_QUERY_TIMESTAMP
}
QD3D11CommandBuffer::Command &cmd(ofr.cbWrapper.commands.get());
cmd.cmd = QD3D11CommandBuffer::Command::EndFrame;
cmd.args.endFrame.tsQuery = ofr.tsQueries[1] ? ofr.tsQueries[1] : nullptr;
cmd.args.endFrame.tsDisjointQuery = ofr.tsDisjointQuery ? ofr.tsDisjointQuery : nullptr;
executeCommandBuffer(&ofr.cbWrapper);
context->Flush();
finishActiveReadbacks();
if (recordTimestamps) {
context->End(tsEnd);
context->End(tsDisjoint);
ofr.timestamps.active[ofr.timestampIdx] = true;
ofr.timestampIdx = (ofr.timestampIdx + 1) % 2;
if (ofr.tsQueries[0]) {
quint64 timestamps[2];
D3D11_QUERY_DATA_TIMESTAMP_DISJOINT dj;
HRESULT hr;
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;
@ -1558,7 +1660,7 @@ QRhi::FrameOpResult QRhiD3D11::finish()
} else {
Q_ASSERT(contextState.currentSwapChain);
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();
}
}
@ -1933,19 +2035,6 @@ void QRhiD3D11::finishActiveReadbacks()
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)
{
Q_ASSERT(QRHI_RES(QD3D11CommandBuffer, cb)->recordingPass == QD3D11CommandBuffer::NoPass);
@ -2651,7 +2740,7 @@ void QRhiD3D11::resetShaderResources()
currentShaderMask &= ~StageU##MaskBit; \
}
void QRhiD3D11::executeCommandBuffer(QD3D11CommandBuffer *cbD, QD3D11SwapChain *timestampSwapChain)
void QRhiD3D11::executeCommandBuffer(QD3D11CommandBuffer *cbD)
{
quint32 stencilRef = 0;
float blendConstants[] = { 1, 1, 1, 1 };
@ -2664,26 +2753,30 @@ void QRhiD3D11::executeCommandBuffer(QD3D11CommandBuffer *cbD, QD3D11SwapChain *
};
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) {
const QD3D11CommandBuffer::Command &cmd(*it);
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:
resetShaderResources();
break;
@ -4702,14 +4795,13 @@ void QD3D11CommandBuffer::destroy()
// 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
// function is expected to be a no-op.
Q_ASSERT(pairCount <= MAX_TIMESTAMP_PAIRS);
D3D11_QUERY_DESC queryDesc = {};
for (int i = 0; i < pairCount; ++i) {
for (int i = 0; i < TIMESTAMP_PAIRS; ++i) {
if (!disjointQuery[i]) {
queryDesc.Query = D3D11_QUERY_TIMESTAMP_DISJOINT;
HRESULT hr = rhiD->dev->CreateQuery(&queryDesc, &disjointQuery[i]);
@ -4721,7 +4813,7 @@ bool QD3D11Timestamps::prepare(int pairCount, QRhiD3D11 *rhiD)
}
queryDesc.Query = D3D11_QUERY_TIMESTAMP;
for (int j = 0; j < 2; ++j) {
const int idx = pairCount * i + j;
const int idx = 2 * i + j;
if (!query[idx]) {
HRESULT hr = rhiD->dev->CreateQuery(&queryDesc, &query[idx]);
if (FAILED(hr)) {
@ -4732,20 +4824,19 @@ bool QD3D11Timestamps::prepare(int pairCount, QRhiD3D11 *rhiD)
}
}
}
this->pairCount = pairCount;
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;
if (disjointQuery[i]) {
disjointQuery[i]->Release();
disjointQuery[i] = nullptr;
}
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]) {
query[idx]->Release();
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;
if (!active[idx])
if (!active[pairIndex])
return result;
ID3D11Query *tsDisjoint = disjointQuery[idx];
const int tsIdx = pairCount * idx;
ID3D11Query *tsStart = query[tsIdx];
ID3D11Query *tsEnd = query[tsIdx + 1];
ID3D11Query *tsDisjoint = disjointQuery[pairIndex];
ID3D11Query *tsStart = query[pairIndex * 2];
ID3D11Query *tsEnd = query[pairIndex * 2 + 1];
quint64 timestamps[2];
D3D11_QUERY_DATA_TIMESTAMP_DISJOINT dj;
bool ok = true;
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;
// 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;
if (ok) {
@ -4782,16 +4868,14 @@ bool QD3D11Timestamps::tryQueryTimestamps(int idx, ID3D11DeviceContext *context,
*elapsedSec = elapsedMs / 1000.0;
result = true;
}
active[idx] = false;
} // else leave active set, will retry in a subsequent beginFrame or similar
active[pairIndex] = false;
} // else leave active set, will retry in a subsequent beginFrame
return result;
}
QD3D11SwapChain::QD3D11SwapChain(QRhiImplementation *rhi)
: QRhiSwapChain(rhi),
rt(rhi, this),
cb(rhi)
: QRhiSwapChain(rhi), rt(rhi, this), rtRight(rhi, this), cb(rhi)
{
backBufferTex = nullptr;
backBufferRtv = nullptr;
@ -4812,6 +4896,10 @@ void QD3D11SwapChain::releaseBuffers()
backBufferRtv->Release();
backBufferRtv = nullptr;
}
if (backBufferRtvRight) {
backBufferRtvRight->Release();
backBufferRtvRight = nullptr;
}
if (backBufferTex) {
backBufferTex->Release();
backBufferTex = nullptr;
@ -4869,50 +4957,17 @@ QRhiRenderTarget *QD3D11SwapChain::currentFrameRenderTarget()
return &rt;
}
QRhiRenderTarget *QD3D11SwapChain::currentFrameRenderTarget(StereoTargetBuffer targetBuffer)
{
return targetBuffer == StereoTargetBuffer::LeftBuffer? &rt: &rtRight;
}
QSize QD3D11SwapChain::surfacePixelSize()
{
Q_ASSERT(m_window);
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)
{
if (f == SDR)
@ -4925,7 +4980,7 @@ bool QD3D11SwapChain::isFormatSupported(Format f)
QRHI_RES_RHI(QRhiD3D11);
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)
return f == QRhiSwapChain::HDRExtendedSrgbLinear || f == QRhiSwapChain::HDR10;
}
@ -4936,14 +4991,16 @@ bool QD3D11SwapChain::isFormatSupported(Format f)
QRhiSwapChainHdrInfo QD3D11SwapChain::hdrInfo()
{
QRhiSwapChainHdrInfo info = QRhiSwapChain::hdrInfo();
// Must use m_window, not window, given this may be called before createOrResize().
if (m_window) {
QRHI_RES_RHI(QRhiD3D11);
DXGI_OUTPUT_DESC1 hdrOutputDesc;
if (outputDesc1ForWindow(m_window, rhiD->activeAdapter, &hdrOutputDesc)) {
info.isHardCodedDefaults = false;
if (QRhiD3D::outputDesc1ForWindow(m_window, rhiD->activeAdapter, &hdrOutputDesc)) {
info.limitsType = QRhiSwapChainHdrInfo::LuminanceInNits;
info.limits.luminanceInNits.minLuminance = hdrOutputDesc.MinLuminance;
info.limits.luminanceInNits.maxLuminance = hdrOutputDesc.MaxLuminance;
info.luminanceBehavior = QRhiSwapChainHdrInfo::SceneReferred; // 1.0 = 80 nits
info.sdrWhiteLevel = QRhiD3D::sdrWhiteLevelInNits(hdrOutputDesc);
}
}
return info;
@ -5016,11 +5073,13 @@ bool QD3D11SwapChain::createOrResize()
{
return createOrResizeWin7();
}
// Can be called multiple times due to window resizes - that is not the
// same as a simple destroy+create (as with other resources). Just need to
// resize the buffers then.
const bool needsRegistration = !window || window != m_window;
const bool stereo = m_window->format().stereo();
// except if the window actually changes
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_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
if (hdrOutputDesc.ColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020) {
switch (m_format) {
@ -5120,6 +5179,7 @@ bool QD3D11SwapChain::createOrResize()
desc.Flags = swapChainFlags;
desc.Scaling = rhiD->useLegacySwapchainModel ? DXGI_SCALING_STRETCH : DXGI_SCALING_NONE;
desc.SwapEffect = rhiD->useLegacySwapchainModel ? DXGI_SWAP_EFFECT_DISCARD : DXGI_SWAP_EFFECT_FLIP_DISCARD;
desc.Stereo = stereo;
if (dcompVisual) {
// With DirectComposition setting AlphaMode to STRAIGHT fails the
@ -5238,6 +5298,19 @@ bool QD3D11SwapChain::createOrResize()
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.
for (int i = 0; i < BUFFER_COUNT; ++i) {
if (sampleDesc.Count > 1) {
@ -5276,8 +5349,20 @@ bool QD3D11SwapChain::createOrResize()
rtD->d.colorAttCount = 1;
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)) {
timestamps.prepare(BUFFER_COUNT, rhiD);
timestamps.prepare(rhiD);
// 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 {
enum Cmd {
BeginFrame,
EndFrame,
ResetShaderResources,
SetRenderTarget,
Clear,
@ -385,6 +387,15 @@ struct QD3D11CommandBuffer : public QRhiCommandBuffer
// QRhi*/QD3D11* references should be kept at minimum (so no
// QRhiTexture/Buffer/etc. pointers).
union Args {
struct {
ID3D11Query *tsQuery;
ID3D11Query *tsDisjointQuery;
QD3D11RenderTargetData *swapchainData;
} beginFrame;
struct {
ID3D11Query *tsQuery;
ID3D11Query *tsDisjointQuery;
} endFrame;
struct {
QRhiRenderTarget *rt;
} setRenderTarget;
@ -556,17 +567,15 @@ struct QD3D11CommandBuffer : public QRhiCommandBuffer
}
};
static const int QD3D11_SWAPCHAIN_BUFFER_COUNT = 2;
struct QD3D11Timestamps
struct QD3D11SwapChainTimestamps
{
static const int MAX_TIMESTAMP_PAIRS = QD3D11_SWAPCHAIN_BUFFER_COUNT;
bool active[MAX_TIMESTAMP_PAIRS] = {};
ID3D11Query *disjointQuery[MAX_TIMESTAMP_PAIRS] = {};
ID3D11Query *query[MAX_TIMESTAMP_PAIRS * 2] = {};
int pairCount = 0;
static const int TIMESTAMP_PAIRS = 2;
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();
bool tryQueryTimestamps(int idx, ID3D11DeviceContext *context, double *elapsedSec);
};
@ -579,6 +588,7 @@ struct QD3D11SwapChain : public QRhiSwapChain
QRhiCommandBuffer *currentFrameCommandBuffer() override;
QRhiRenderTarget *currentFrameRenderTarget() override;
QRhiRenderTarget *currentFrameRenderTarget(StereoTargetBuffer targetBuffer) override;
QSize surfacePixelSize() override;
bool isFormatSupported(Format f) override;
@ -587,7 +597,7 @@ struct QD3D11SwapChain : public QRhiSwapChain
QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() override;
bool createOrResize() override;
bool createOrResizeWin7();
void releaseBuffers();
bool newColorBuffer(const QSize &size, DXGI_FORMAT format, DXGI_SAMPLE_DESC sampleDesc,
ID3D11Texture2D **tex, ID3D11RenderTargetView **rtv) const;
@ -595,6 +605,7 @@ struct QD3D11SwapChain : public QRhiSwapChain
QWindow *window = nullptr;
QSize pixelSize;
QD3D11SwapChainRenderTarget rt;
QD3D11SwapChainRenderTarget rtRight;
QD3D11CommandBuffer cb;
DXGI_FORMAT colorFormat;
DXGI_FORMAT srgbAdjustedColorFormat;
@ -602,7 +613,8 @@ struct QD3D11SwapChain : public QRhiSwapChain
UINT swapChainFlags = 0;
ID3D11Texture2D *backBufferTex;
ID3D11RenderTargetView *backBufferRtv;
static const int BUFFER_COUNT = QD3D11_SWAPCHAIN_BUFFER_COUNT;
ID3D11RenderTargetView *backBufferRtvRight = nullptr;
static const int BUFFER_COUNT = 2;
ID3D11Texture2D *msaaTex[BUFFER_COUNT];
ID3D11RenderTargetView *msaaRtv[BUFFER_COUNT];
DXGI_SAMPLE_DESC sampleDesc;
@ -612,7 +624,8 @@ struct QD3D11SwapChain : public QRhiSwapChain
UINT swapInterval = 1;
IDCompositionTarget *dcompTarget = nullptr;
IDCompositionVisual *dcompVisual = nullptr;
QD3D11Timestamps timestamps;
QD3D11SwapChainTimestamps timestamps;
int currentTimestampPairIndex = 0;
};
class QRhiD3D11 : public QRhiImplementation
@ -737,7 +750,7 @@ public:
const uint *dynOfsPairs, int dynOfsPairCount,
bool offsetOnlyChange);
void resetShaderResources();
void executeCommandBuffer(QD3D11CommandBuffer *cbD, QD3D11SwapChain *timestampSwapChain = nullptr);
void executeCommandBuffer(QD3D11CommandBuffer *cbD);
DXGI_SAMPLE_DESC effectiveSampleDesc(int sampleCount) const;
void finishActiveReadbacks();
void reportLiveObjects(ID3D11Device *device);
@ -780,8 +793,8 @@ public:
OffscreenFrame(QRhiImplementation *rhi) : cbWrapper(rhi) { }
bool active = false;
QD3D11CommandBuffer cbWrapper;
QD3D11Timestamps timestamps;
int timestampIdx = 0;
ID3D11Query *tsQueries[2] = {};
ID3D11Query *tsDisjointQuery = nullptr;
} ofr;
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));
m_fontDatas.insert(key, fontData);
if (!m_fontDatas.contains(fontData.data()))
m_fontDatas.insert(fontData.data(), fontData);
}
inline void removeKey(const void *key)
@ -378,6 +378,11 @@ namespace {
UINT32 fontFileReferenceKeySize,
OUT IDWriteFontFileStream **fontFileStream) override;
void clear()
{
m_fontDatas.clear();
}
private:
ULONG m_referenceCount;
QHash<const void *, QByteArray> m_fontDatas;
@ -435,53 +440,63 @@ namespace {
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
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
@ -550,8 +565,12 @@ void QWindowsFontDatabaseBase::createDirectWriteFactory(IDWriteFactory **factory
IUnknown *result = nullptr;
# 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
if (result == nullptr)
DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory2), &result);
@ -700,28 +719,47 @@ QFont QWindowsFontDatabaseBase::systemDefaultFont()
return systemFont;
}
#if QT_CONFIG(directwrite) && QT_CONFIG(direct2d)
IDWriteFontFace *QWindowsFontDatabaseBase::createDirectWriteFace(const QByteArray &fontData) const
void QWindowsFontDatabaseBase::invalidate()
{
#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();
if (fontEngineData->directWriteFactory == nullptr) {
qCWarning(lcQpaFonts) << "DirectWrite factory not created in QWindowsFontDatabaseBase::createDirectWriteFace()";
return nullptr;
return ret;
}
CustomFontFileLoader fontFileLoader(fontEngineData->directWriteFactory);
fontFileLoader.addKey(this, fontData);
if (m_fontFileLoader == nullptr)
m_fontFileLoader.reset(new QCustomFontFileLoader(fontEngineData->directWriteFactory));
m_fontFileLoader->addKey(fontData);
IDWriteFontFile *fontFile = nullptr;
const void *key = this;
const void *key = fontData.data();
HRESULT hres = fontEngineData->directWriteFactory->CreateCustomFontFileReference(&key,
sizeof(void *),
fontFileLoader.loader(),
m_fontFileLoader->loader(),
&fontFile);
if (FAILED(hres)) {
qErrnoWarning(hres, "%s: CreateCustomFontFileReference failed", __FUNCTION__);
return nullptr;
return ret;
}
BOOL isSupportedFontType;
@ -731,25 +769,65 @@ IDWriteFontFace *QWindowsFontDatabaseBase::createDirectWriteFace(const QByteArra
fontFile->Analyze(&isSupportedFontType, &fontFileType, &fontFaceType, &numberOfFaces);
if (!isSupportedFontType) {
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.
IDWriteFontFace *directWriteFontFace = nullptr;
hres = fontEngineData->directWriteFactory->CreateFontFace(fontFaceType,
1,
&fontFile,
0,
DWRITE_FONT_SIMULATIONS_NONE,
&directWriteFontFace);
if (FAILED(hres)) {
qErrnoWarning(hres, "%s: CreateFontFace failed", __FUNCTION__);
fontFile->Release();
return nullptr;
if (ret.isEmpty()) {
IDWriteFontFace *directWriteFontFace = nullptr;
hres = fontEngineData->directWriteFactory->CreateFontFace(fontFaceType,
1,
&fontFile,
0,
DWRITE_FONT_SIMULATIONS_NONE,
&directWriteFontFace);
if (FAILED(hres)) {
qErrnoWarning(hres, "%s: CreateFontFace failed", __FUNCTION__);
fontFile->Release();
return ret;
} else {
ret.append(directWriteFontFace);
}
}
fontFile->Release();
return directWriteFontFace;
return ret;
}
#endif // directwrite && direct2d
@ -769,7 +847,10 @@ QFontEngine *QWindowsFontDatabaseBase::fontEngine(const QByteArray &fontData, qr
if (fontEngineData->directWriteFactory == nullptr)
return nullptr;
IDWriteFontFace *directWriteFontFace = createDirectWriteFace(fontData);
IDWriteFontFace * directWriteFontFace = createDirectWriteFace(fontData);
if (directWriteFontFace == nullptr)
return nullptr;
fontEngine = new QWindowsFontEngineDirectWrite(directWriteFontFace,
pixelSize,
fontEngineData);

View File

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

View File

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

View File

@ -28,9 +28,13 @@
#include <QtCore/qdebug.h>
#include <QtCore/qbuffer.h>
#include <QtCore/qpoint.h>
#include <QtCore/qpointer.h>
#include <QtCore/private/qcomobject_p.h>
#include <shlobj.h>
#include "vxkex.h"
QT_BEGIN_NAMESPACE
/*!
@ -167,7 +171,7 @@ static Qt::MouseButtons lastButtons = Qt::NoButton;
\internal
*/
class QWindowsOleDropSource : public QWindowsComBase<IDropSource>
class QWindowsOleDropSource : public QComObject<IDropSource>
{
public:
enum Mode {
@ -526,7 +530,8 @@ QWindowsOleDropTarget::DragLeave()
qCDebug(lcQpaMime) << __FUNCTION__ << ' ' << m_window;
lastModifiers = QWindowsKeyMapper::queryKeyboardModifiers();
const auto *keyMapper = QWindowsContext::instance()->keyMapper();
lastModifiers = keyMapper->queryKeyboardModifiers();
lastButtons = QWindowsMouseHandler::queryMouseButtons();
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_dragging = false;
QWindowsDrag::QWindowsDrag() = default;
@ -671,7 +675,11 @@ static HRESULT startDoDragDrop(LPDATAOBJECT pDataObj, LPDROPSOURCE pDropSource,
const quint32 pointerId = GET_POINTERID_WPARAM(msg.wParam);
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;
if (pointerInfo.pointerFlags & POINTER_FLAG_PRIMARY) {
@ -739,10 +747,7 @@ Qt::DropAction QWindowsDrag::drag(QDrag *drag)
const DWORD allowedEffects = translateToWinDragEffects(possibleActions);
qCDebug(lcQpaMime) << '>' << __FUNCTION__ << "possible Actions=0x"
<< 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);
QWindowsDrag::m_dragging = false;
const DWORD reportedPerformedEffect = dropDataObject->reportedPerformedEffect();
if (r == DRAGDROP_S_DROP) {
if (reportedPerformedEffect == DROPEFFECT_MOVE && resultEffect != DROPEFFECT_MOVE) {

View File

@ -17,6 +17,8 @@
#include <QtCore/private/qdebug_p.h>
#include <QtCore/private/qtools_p.h>
#include "vxkex.h"
#if defined(WM_APPCOMMAND)
# ifndef FAPPCOMMAND_MOUSE
# define FAPPCOMMAND_MOUSE 0x8000
@ -88,9 +90,17 @@ QWindowsKeyMapper::~QWindowsKeyMapper()= default;
#define VK_OEM_3 0xC0
#endif
// We not only need the scancode itself but also the extended bit of key messages. Thus we need
// the additional bit when masking the scancode.
enum { scancodeBitmask = 0x1ff };
// Get scancode from the given message
static constexpr quint32 getScancode(const MSG &msg)
{
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 ] --
struct KeyRecord {
@ -532,33 +542,6 @@ QDebug operator<<(QDebug d, const KeyboardLayoutItem &k)
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
/**
@ -656,7 +639,7 @@ void QWindowsKeyMapper::updateKeyMap(const MSG &msg)
{
unsigned char kbdBuffer[256]; // Will hold the complete keyboard state
GetKeyboardState(kbdBuffer);
const quint32 scancode = (msg.lParam >> 16) & scancodeBitmask;
const quint32 scancode = getScancode(msg);
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)
{
if (QWindowsContext::user32dll.getDpiForWindow && QWindowsContext::user32dll.getSystemMetricsForDpi)
{
const UINT dpi = QWindowsContext::user32dll.getDpiForWindow(hwnd);
const int captionHeight = QWindowsContext::user32dll.getSystemMetricsForDpi(SM_CYCAPTION, dpi);
if (IsZoomed(hwnd))
return captionHeight;
// The frame height should also be taken into account if the window
// is not maximized.
const int frameHeight = QWindowsContext::user32dll.getSystemMetricsForDpi(SM_CYSIZEFRAME, dpi)
+ QWindowsContext::user32dll.getSystemMetricsForDpi(SM_CXPADDEDBORDER, dpi);
return captionHeight + frameHeight;
}
else
{
const int captionHeight = GetSystemMetrics(SM_CYCAPTION);
if (IsZoomed(hwnd))
return captionHeight;
// The frame height should also be taken into account if the window
// is not maximized.
const int frameHeight = GetSystemMetrics(SM_CYSIZEFRAME) + GetSystemMetrics(SM_CXPADDEDBORDER);
return captionHeight + frameHeight;
}
const BOOL bNewAPI = (QWindowsContext::user32dll.getSystemMetricsForDpi != nullptr);
const UINT dpi = bNewAPI ? QWindowsContext::user32dll.getDpiForWindow(hwnd) : vxkex::GetDpiForWindow(hwnd);
const int captionHeight = bNewAPI ? QWindowsContext::user32dll.getSystemMetricsForDpi(SM_CYCAPTION, dpi) : vxkex::GetSystemMetricsForDpi(SM_CYCAPTION, dpi);
if (IsZoomed(hwnd))
return captionHeight;
// The frame height should also be taken into account if the window
// is not maximized.
const int frameHeight = bNewAPI ?
(QWindowsContext::user32dll.getSystemMetricsForDpi(SM_CYSIZEFRAME, dpi) + QWindowsContext::user32dll.getSystemMetricsForDpi(SM_CXPADDEDBORDER, dpi))
: (vxkex::GetSystemMetricsForDpi(SM_CYSIZEFRAME, dpi) + vxkex::GetSystemMetricsForDpi(SM_CXPADDEDBORDER, dpi));
return captionHeight + frameHeight;
}
[[nodiscard]] static inline bool isSystemMenuOffsetNeeded(const Qt::WindowFlags flags)
@ -955,7 +928,7 @@ bool QWindowsKeyMapper::translateKeyEventInternal(QWindow *window, MSG msg,
m_seenAltGr = true;
const UINT msgType = msg.message;
const quint32 scancode = (msg.lParam >> 16) & scancodeBitmask;
const quint32 scancode = getScancode(msg);
auto vk_key = quint32(msg.wParam);
quint32 nModifiers = 0;
@ -1352,7 +1325,7 @@ bool QWindowsKeyMapper::translateKeyEventInternal(QWindow *window, MSG msg,
return result;
}
Qt::KeyboardModifiers QWindowsKeyMapper::queryKeyboardModifiers()
Qt::KeyboardModifiers QWindowsKeyMapper::queryKeyboardModifiers() const
{
Qt::KeyboardModifiers modifiers = Qt::NoModifier;
if (GetKeyState(VK_SHIFT) < 0)
@ -1366,9 +1339,9 @@ Qt::KeyboardModifiers QWindowsKeyMapper::queryKeyboardModifiers()
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();
@ -1382,31 +1355,34 @@ QList<int> QWindowsKeyMapper::possibleKeys(const QKeyEvent *e) const
quint32 baseKey = kbItem.qtKey[0];
Qt::KeyboardModifiers keyMods = e->modifiers();
if (baseKey == Qt::Key_Return && (e->nativeModifiers() & ExtendedKey)) {
result << (Qt::Key_Enter | keyMods).toCombined();
result << (Qt::Key_Enter | keyMods);
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) {
Qt::KeyboardModifiers neededMods = ModsTbl[i];
quint32 key = kbItem.qtKey[i];
if (key && key != baseKey && ((keyMods & neededMods) == neededMods)) {
const Qt::KeyboardModifiers missingMods = keyMods & ~neededMods;
const int matchedKey = int(key) + int(missingMods);
const auto it =
std::find_if(result.begin(), result.end(),
[key] (int k) { return (k & ~Qt::KeyboardModifierMask) == key; });
const auto matchedKey = QKeyCombination::fromCombined(int(key) + int(missingMods));
const auto it = std::find_if(result.begin(), result.end(),
[key](auto keyCombination) {
return keyCombination.key() == key;
});
// QTBUG-67200: Use the match with the least modifiers (prefer
// Shift+9 over Alt + Shift + 9) resulting in more missing modifiers.
if (it == result.end())
result << matchedKey;
else if (missingMods > Qt::KeyboardModifiers(*it & Qt::KeyboardModifierMask))
else if (missingMods > it->keyboardModifiers())
*it = matchedKey;
}
}
qCDebug(lcQpaEvents) << __FUNCTION__ << e << "nativeVirtualKey="
<< 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;
}

View File

@ -27,6 +27,8 @@
#include <windowsx.h>
#include "vxkex.h"
QT_BEGIN_NAMESPACE
enum {
@ -48,7 +50,11 @@ bool QWindowsPointerHandler::translatePointerEvent(QWindow *window, HWND hwnd, Q
*result = 0;
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();
return false;
}
@ -62,12 +68,21 @@ bool QWindowsPointerHandler::translatePointerEvent(QWindow *window, HWND hwnd, Q
}
case QT_PT_TOUCH: {
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();
return false;
}
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();
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
if (historyCount > 1 && !QCoreApplication::testAttribute(Qt::AA_CompressHighFrequencyEvents)) {
touchInfo.resize(pointerCount * historyCount);
if (!QWindowsContext::user32dll.getPointerFrameTouchInfoHistory(pointerId,
&historyCount,
&pointerCount,
touchInfo.data())) {
BOOL bResultTouchHistory = QWindowsContext::user32dll.getPointerFrameTouchInfoHistory ?
QWindowsContext::user32dll.getPointerFrameTouchInfoHistory(pointerId, &historyCount, &pointerCount, touchInfo.data()) :
vxkex::GetPointerFrameTouchInfoHistory(pointerId, &historyCount, &pointerCount, touchInfo.data());
if (!bResultTouchHistory) {
qWarning() << "GetPointerFrameTouchInfoHistory() failed:" << qt_error_string();
return false;
}
@ -101,7 +118,11 @@ bool QWindowsPointerHandler::translatePointerEvent(QWindow *window, HWND hwnd, Q
}
case QT_PT_PEN: {
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();
return false;
}
@ -113,7 +134,11 @@ bool QWindowsPointerHandler::translatePointerEvent(QWindow *window, HWND hwnd, Q
|| !QCoreApplication::testAttribute(Qt::AA_CompressTabletEvents))) {
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();
return false;
}
@ -428,8 +453,9 @@ bool QWindowsPointerHandler::translateTouchEvent(QWindow *window, HWND hwnd,
return false;
if (msg.message == WM_POINTERCAPTURECHANGED) {
const auto *keyMapper = QWindowsContext::instance()->keyMapper();
QWindowSystemInterface::handleTouchCancelEvent(window, m_touchDevice.data(),
QWindowsKeyMapper::queryKeyboardModifiers());
keyMapper->queryKeyboardModifiers());
m_lastTouchPoints.clear();
return true;
}
@ -519,7 +545,10 @@ bool QWindowsPointerHandler::translateTouchEvent(QWindow *window, HWND hwnd,
inputIds.insert(touchPoint.id);
// 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
@ -539,8 +568,9 @@ bool QWindowsPointerHandler::translateTouchEvent(QWindow *window, HWND hwnd,
if (allStates == QEventPoint::State::Released)
m_touchInputIDToTouchPointID.clear();
const auto *keyMapper = QWindowsContext::instance()->keyMapper();
QWindowSystemInterface::handleTouchEvent(window, m_touchDevice.data(), touchPoints,
QWindowsKeyMapper::queryKeyboardModifiers());
keyMapper->queryKeyboardModifiers());
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);
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;
const auto systemId = (qint64)penInfo->pointerInfo.sourceDevice;
@ -673,7 +708,8 @@ bool QWindowsPointerHandler::translatePenEvent(QWindow *window, HWND hwnd, QtWin
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(),
localPos, hiResGlobalPos, mouseButtons,
@ -762,7 +798,8 @@ bool QWindowsPointerHandler::translateMouseEvent(QWindow *window,
: 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);
if (et == QtWindows::MouseWheelEvent)

View File

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

View File

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

View File

@ -27,6 +27,7 @@
#include <QtGui/qwindow.h>
#include <QtGui/qregion.h>
#include <QtGui/qopenglcontext.h>
#include <QtGui/private/qwindowsthemecache_p.h>
#include <private/qwindow_p.h> // QWINDOWSIZE_MAX
#include <private/qguiapplication_p.h>
#include <private/qhighdpiscaling_p.h>
@ -43,6 +44,8 @@
#include <shellscalingapi.h>
#include "vxkex.h"
QT_BEGIN_NAMESPACE
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)
+ QWindowsContext::user32dll.getSystemMetricsForDpi(SM_CXPADDEDBORDER, dpi);
}
return GetSystemMetrics(SM_CXSIZEFRAME) + GetSystemMetrics(SM_CXPADDEDBORDER);
else
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)
{
if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows10) {
POINT pt = {screenPoint.x(), screenPoint.y()};
if (HMONITOR hMonitor = MonitorFromPoint(pt, MONITOR_DEFAULTTONULL)) {
if (QWindowsContext::shcoredll.isValid()) {
UINT dpiX;
UINT dpiY;
if (SUCCEEDED(QWindowsContext::shcoredll.getDpiForMonitor(hMonitor, MDT_EFFECTIVE_DPI, &dpiX, &dpiY))) {
const int gap = getResizeBorderThickness(dpiX);
return QMargins(gap, 0, gap, gap);
}
POINT pt = {screenPoint.x(), screenPoint.y()};
if (HMONITOR hMonitor = MonitorFromPoint(pt, MONITOR_DEFAULTTONULL)) {
if (QWindowsContext::shcoredll.isValid()) {
UINT dpiX;
UINT dpiY;
HRESULT hr = S_OK;
if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows10)
hr = QWindowsContext::shcoredll.getDpiForMonitor(hMonitor, MDT_EFFECTIVE_DPI, &dpiX, &dpiY);
else
hr = vxkex::GetDpiForMonitor(hMonitor, MDT_EFFECTIVE_DPI, &dpiX, &dpiY);
if (SUCCEEDED(hr)) {
const int gap = getResizeBorderThickness(dpiX);
return QMargins(gap, 0, gap, gap);
}
}
}
@ -555,12 +564,10 @@ static QMargins invisibleMargins(QPoint screenPoint)
[[nodiscard]] static inline QMargins invisibleMargins(const HWND hwnd)
{
if (QWindowsContext::user32dll.getDpiForWindow) {
const UINT dpi = QWindowsContext::user32dll.getDpiForWindow(hwnd);
const int gap = getResizeBorderThickness(dpi);
return QMargins(gap, 0, gap, gap);
}
return QMargins();
const UINT dpi = (QWindowsContext::user32dll.getDpiForWindow) ? QWindowsContext::user32dll.getDpiForWindow(hwnd) : vxkex::GetDpiForWindow(hwnd);
const int gap = getResizeBorderThickness(dpi);
return QMargins(gap, 0, gap, gap);
}
/*!
@ -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
if (flagsIn & Qt::WindowTransparentForInput)
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 {};
RECT rect = {0,0,0,0};
style &= ~DWORD(WS_OVERLAPPED); // Not permitted, see docs.
if (QWindowsContext::user32dll.adjustWindowRectExForDpi &&
QWindowsContext::user32dll.adjustWindowRectExForDpi(&rect, style, FALSE, exStyle, unsigned(qRound(dpi))) == FALSE) {
qErrnoWarning("%s: AdjustWindowRectExForDpi failed", __FUNCTION__);
if (QWindowsContext::user32dll.adjustWindowRectExForDpi)
{
if (QWindowsContext::user32dll.adjustWindowRectExForDpi(&rect, style, FALSE, exStyle, unsigned(qRound(dpi))) == FALSE)
qErrnoWarning("%s: AdjustWindowRectExForDpi failed", __FUNCTION__);
}
else
{
if (vxkex::AdjustWindowRectExForDpi(&rect, style, FALSE, exStyle, unsigned(qRound(dpi))) == FALSE)
qErrnoWarning("%s: vxkex::AdjustWindowRectExForDpi failed", __FUNCTION__);
}
const QMargins result(qAbs(rect.left), qAbs(rect.top),
qAbs(rect.right), qAbs(rect.bottom));
qCDebug(lcQpaWindow).nospace() << __FUNCTION__ << " style="
@ -1364,6 +1382,8 @@ QWindowsForeignWindow::QWindowsForeignWindow(QWindow *window, HWND hwnd)
, m_hwnd(hwnd)
, m_topLevelStyle(0)
{
if (QPlatformWindow::parent())
setParent(QPlatformWindow::parent());
}
void QWindowsForeignWindow::setParent(const QPlatformWindow *newParentWindow)
@ -1539,6 +1559,7 @@ QWindowsWindow::QWindowsWindow(QWindow *aWindow, const QWindowsWindowData &data)
QWindowsWindow::~QWindowsWindow()
{
setFlag(WithinDestroy);
QWindowsThemeCache::clearThemeCache(m_data.hwnd);
if (testFlag(TouchRegistered))
UnregisterTouchWindow(m_data.hwnd);
destroyWindow();
@ -1568,7 +1589,7 @@ void QWindowsWindow::initialize()
}
}
QWindowsWindow::setSavedDpi(QWindowsContext::user32dll.getDpiForWindow ?
QWindowsContext::user32dll.getDpiForWindow(handle()) : 96);
QWindowsContext::user32dll.getDpiForWindow(handle()) : vxkex::GetDpiForWindow(handle()));
}
QSurfaceFormat QWindowsWindow::format() const
@ -2018,6 +2039,9 @@ void QWindowsWindow::handleDpiChanged(HWND hwnd, WPARAM wParam, LPARAM lParam)
const UINT dpi = HIWORD(wParam);
const qreal scale = dpiRelativeScale(dpi);
setSavedDpi(dpi);
QWindowsThemeCache::clearThemeCache(hwnd);
// Send screen change first, so that the new screen is set during any following resize
checkForScreenChanged(QWindowsWindow::FromDpiChange);
@ -2060,20 +2084,17 @@ void QWindowsWindow::handleDpiChanged(HWND hwnd, WPARAM wParam, LPARAM lParam)
void QWindowsWindow::handleDpiChangedAfterParent(HWND hwnd)
{
if (QWindowsContext::user32dll.getDpiForWindow)
{
const UINT dpi = QWindowsContext::user32dll.getDpiForWindow(hwnd);
const qreal scale = dpiRelativeScale(dpi);
setSavedDpi(dpi);
const UINT dpi = QWindowsContext::user32dll.getDpiForWindow ? QWindowsContext::user32dll.getDpiForWindow(hwnd) : vxkex::GetDpiForWindow(hwnd);
const qreal scale = dpiRelativeScale(dpi);
setSavedDpi(dpi);
checkForScreenChanged(QWindowsWindow::FromDpiChange);
checkForScreenChanged(QWindowsWindow::FromDpiChange);
// Child windows do not get WM_GETDPISCALEDSIZE messages to inform
// Windows about the new size, so we need to manually scale them.
QRect currentGeometry = geometry();
QRect scaledGeometry = QRect(currentGeometry.topLeft() * scale, currentGeometry.size() * scale);
setGeometry(scaledGeometry);
}
// Child windows do not get WM_GETDPISCALEDSIZE messages to inform
// Windows about the new size, so we need to manually scale them.
QRect currentGeometry = geometry();
QRect scaledGeometry = QRect(currentGeometry.topLeft() * scale, currentGeometry.size() * scale);
setGeometry(scaledGeometry);
}
static QRect normalFrameGeometry(HWND hwnd)
@ -2485,6 +2506,11 @@ void QWindowsWindow::handleWindowStateChange(Qt::WindowStates state)
GetWindowPlacement(m_data.hwnd, &windowPlacement);
const RECT geometry = RECTfromQRect(m_data.restoreGeometry);
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);
}
// 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