4 Commits

11 changed files with 55 additions and 51 deletions

View File

@ -1,10 +1,10 @@
This repository provides a backport of the Qt 6.8.1 qtbase module, tailored for compatibility with Windows 7, 8 and 8.1. It contains patched source files from the qtbase module, along with some additional required files. To apply the backport, simply copy the contents of the src folder into your qtbase/src directory, replacing the existing files. This repository provides a backport of the Qt 6.8.2 qtbase module, tailored for compatibility with Windows 7, 8 and 8.1. It contains patched source files from the qtbase module, along with some additional required files. To apply the backport, simply copy the contents of the src folder into your qtbase/src directory, replacing the existing files.
This approach builds upon the methodology discussed in this forum [thread](https://forum.qt.io/topic/133002/qt-creator-6-0-1-and-qt-6-2-2-running-on-windows-7/60) but offers significant enhancements, including important fallbacks to the default Qt 6 behavior when running on newer versions of Windows. This approach builds upon the methodology discussed in this forum [thread](https://forum.qt.io/topic/133002/qt-creator-6-0-1-and-qt-6-2-2-running-on-windows-7/60) but offers significant enhancements, including important fallbacks to the default Qt 6 behavior when running on newer versions of Windows.
You can compile it yourself using your preferred compiler and build options or can use our [compile_win.pl](https://github.com/crystalidea/qt-build-tools/tree/master/6.8.1) build script, which utilizes Visual C++ 2022 and includes OpenSSL 3.0.13 statically linked. Alternatively, you can download our [prebuild Qt dlls](https://github.com/crystalidea/qt6windows7/releases), which also include the Qt Designer binary for demonstration purposes. You can compile it yourself using your preferred compiler and build options or can use our [compile_win.pl](https://github.com/crystalidea/qt-build-tools/tree/master/6.8.1) build script, which utilizes Visual C++ 2022 and includes OpenSSL 3.0.13 statically linked. Alternatively, you can download our [prebuild Qt dlls](https://github.com/crystalidea/qt6windows7/releases), which also include the Qt Designer binary for demonstration purposes.
**Qt 6.8.1 designer running on Windows 7**: **Qt 6.8.2 designer running on Windows 7**:
![Qt Designer](designer.png) ![Qt Designer](designer.png)
@ -23,6 +23,7 @@ Many of other Qt 6 modules are known to work fine on Windows 7 without modificat
### Older versions: ### Older versions:
- [Qt 6.8.1](https://github.com/crystalidea/qt6windows7/releases/tag/v6.8.1)
- [Qt 6.8.0](https://github.com/crystalidea/qt6windows7/releases/tag/v6.8.0) - [Qt 6.8.0](https://github.com/crystalidea/qt6windows7/releases/tag/v6.8.0)
- [Qt 6.7.2](https://github.com/crystalidea/qt6windows7/releases/tag/v6.7.2) - [Qt 6.7.2](https://github.com/crystalidea/qt6windows7/releases/tag/v6.7.2)
- [Qt 6.6.3](https://github.com/crystalidea/qt6windows7/releases/tag/v6.6.3) - [Qt 6.6.3](https://github.com/crystalidea/qt6windows7/releases/tag/v6.6.3)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 63 KiB

View File

@ -637,6 +637,7 @@ void QRecursiveMutex::unlock() noexcept
/*! /*!
\internal helper for lock() \internal helper for lock()
*/ */
Q_NEVER_INLINE
void QBasicMutex::lockInternal() QT_MUTEX_LOCK_NOEXCEPT void QBasicMutex::lockInternal() QT_MUTEX_LOCK_NOEXCEPT
{ {
if (futexAvailable()) { if (futexAvailable()) {
@ -670,6 +671,7 @@ bool QBasicMutex::lockInternal(int timeout) QT_MUTEX_LOCK_NOEXCEPT
/*! /*!
\internal helper for tryLock(QDeadlineTimer) \internal helper for tryLock(QDeadlineTimer)
*/ */
Q_NEVER_INLINE
bool QBasicMutex::lockInternal(QDeadlineTimer deadlineTimer) QT_MUTEX_LOCK_NOEXCEPT bool QBasicMutex::lockInternal(QDeadlineTimer deadlineTimer) QT_MUTEX_LOCK_NOEXCEPT
{ {
if (deadlineTimer.hasExpired()) if (deadlineTimer.hasExpired())
@ -809,6 +811,7 @@ bool QBasicMutex::lockInternal(QDeadlineTimer deadlineTimer) QT_MUTEX_LOCK_NOEXC
/*! /*!
\internal \internal
*/ */
Q_NEVER_INLINE
void QBasicMutex::unlockInternal() noexcept void QBasicMutex::unlockInternal() noexcept
{ {
QMutexPrivate *copy = d_ptr.loadAcquire(); QMutexPrivate *copy = d_ptr.loadAcquire();

View File

@ -11,6 +11,7 @@
#include <private/qcoreapplication_p.h> #include <private/qcoreapplication_p.h>
#include <private/qeventdispatcher_win_p.h> #include <private/qeventdispatcher_win_p.h>
#include "qloggingcategory.h"
#include <qt_windows.h> #include <qt_windows.h>
@ -352,7 +353,6 @@ void QThreadPrivate::finish(bool lockAnyway) noexcept
if (lockAnyway) if (lockAnyway)
locker.unlock(); locker.unlock();
emit thr->finished(QThread::QPrivateSignal()); emit thr->finished(QThread::QPrivateSignal());
qCDebug(lcDeleteLater) << "Sending deferred delete events as part of finishing thread" << thr;
QCoreApplicationPrivate::sendPostedEvents(nullptr, QEvent::DeferredDelete, d->data); QCoreApplicationPrivate::sendPostedEvents(nullptr, QEvent::DeferredDelete, d->data);
QThreadStorageData::finish(tls_data); QThreadStorageData::finish(tls_data);
if (lockAnyway) if (lockAnyway)

View File

@ -5697,7 +5697,16 @@ bool QD3D12GraphicsPipeline::create()
} }
QD3D12RenderPassDescriptor *rpD = QRHI_RES(QD3D12RenderPassDescriptor, m_renderPassDesc); QD3D12RenderPassDescriptor *rpD = QRHI_RES(QD3D12RenderPassDescriptor, m_renderPassDesc);
const DXGI_SAMPLE_DESC sampleDesc = rhiD->effectiveSampleDesc(m_sampleCount, DXGI_FORMAT(rpD->colorFormat[0])); DXGI_FORMAT format = DXGI_FORMAT_UNKNOWN;
if (rpD->colorAttachmentCount > 0) {
format = DXGI_FORMAT(rpD->colorFormat[0]);
} else if (rpD->hasDepthStencil) {
format = DXGI_FORMAT(rpD->dsFormat);
} else {
qWarning("Cannot create graphics pipeline state without color or depthStencil format");
return false;
}
const DXGI_SAMPLE_DESC sampleDesc = rhiD->effectiveSampleDesc(m_sampleCount, format);
struct { struct {
QD3D12PipelineStateSubObject<ID3D12RootSignature *, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_ROOT_SIGNATURE> rootSig; QD3D12PipelineStateSubObject<ID3D12RootSignature *, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_ROOT_SIGNATURE> rootSig;

View File

@ -134,29 +134,6 @@ bool parseIntOption(const QString &parameter,const QLatin1StringView &option,
using DarkModeHandlingFlag = QNativeInterface::Private::QWindowsApplication::DarkModeHandlingFlag; using DarkModeHandlingFlag = QNativeInterface::Private::QWindowsApplication::DarkModeHandlingFlag;
using DarkModeHandling = QNativeInterface::Private::QWindowsApplication::DarkModeHandling; using DarkModeHandling = QNativeInterface::Private::QWindowsApplication::DarkModeHandling;
typedef LONG (WINAPI *RtlGetVersionPtr)(PRTL_OSVERSIONINFOW);
bool isWindows81() {
HMODULE hNtdll = GetModuleHandleA("ntdll.dll");
if (!hNtdll) {
return false; // Failed to load ntdll.dll
}
RtlGetVersionPtr RtlGetVersion = (RtlGetVersionPtr)GetProcAddress(hNtdll, "RtlGetVersion");
if (!RtlGetVersion) {
return false; // Failed to get RtlGetVersion
}
RTL_OSVERSIONINFOW rovi = {0};
rovi.dwOSVersionInfoSize = sizeof(rovi);
if (RtlGetVersion(&rovi) == 0) { // STATUS_SUCCESS
return (rovi.dwMajorVersion == 6 && rovi.dwMinorVersion == 3);
}
return false; // Unknown version
}
static inline unsigned parseOptions(const QStringList &paramList, static inline unsigned parseOptions(const QStringList &paramList,
int *tabletAbsoluteRange, int *tabletAbsoluteRange,
QtWindows::DpiAwareness *dpiAwareness, QtWindows::DpiAwareness *dpiAwareness,
@ -164,12 +141,6 @@ static inline unsigned parseOptions(const QStringList &paramList,
{ {
unsigned options = 0; unsigned options = 0;
// for some reason DirectWrite fonts don't work on Windows 8.1
// https://github.com/crystalidea/qt6windows7/issues/26
if (isWindows81())
options |= QWindowsIntegration::DontUseDirectWriteFonts;
for (const QString &param : paramList) { for (const QString &param : paramList) {
if (param.startsWith(u"fontengine=")) { if (param.startsWith(u"fontengine=")) {
if (param.endsWith(u"gdi")) { if (param.endsWith(u"gdi")) {
@ -515,7 +486,14 @@ QPlatformFontDatabase *QWindowsIntegration::fontDatabase() const
else else
#endif // QT_NO_FREETYPE #endif // QT_NO_FREETYPE
#if QT_CONFIG(directwrite3) #if QT_CONFIG(directwrite3)
if (!(d->m_options & (QWindowsIntegration::FontDatabaseGDI | QWindowsIntegration::DontUseDirectWriteFonts)))
/* IDWriteFontFace3 is only reportedly available starting with Windows 10. This change is necessary starting
with Qt 6.8, where DirectWrite is used by default to populate the font database.
More info: https://github.com/videolan/vlc/blob/master/contrib/src/qt/0001-Use-DirectWrite-font-database-only-with-Windows-10-a.patch
*/
if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows10 &&
!(d->m_options & (QWindowsIntegration::FontDatabaseGDI | QWindowsIntegration::DontUseDirectWriteFonts)))
d->m_fontDatabase = new QWindowsDirectWriteFontDatabase; d->m_fontDatabase = new QWindowsDirectWriteFontDatabase;
else else
#endif #endif

View File

@ -1359,6 +1359,11 @@ QList<QKeyCombination> QWindowsKeyMapper::possibleKeyCombinations(const QKeyEven
return result; return result;
} }
// If Key_Tab+Shift is pressed we add Key_Backtab without
// shift modifier as a possible combination too
if (baseKey == Qt::Key_Tab && (keyMods & Qt::ShiftModifier))
result << (Qt::Key_Backtab | (keyMods & ~Qt::ShiftModifier));
// The base key is _always_ valid, of course // The base key is _always_ valid, of course
result << QKeyCombination::fromCombined(int(baseKey) + int(keyMods)); result << QKeyCombination::fromCombined(int(baseKey) + int(keyMods));

View File

@ -132,12 +132,12 @@ namespace {
struct DiRegKeyHandleTraits struct DiRegKeyHandleTraits
{ {
using Type = HKEY; using Type = HKEY;
static Type invalidValue() static Type invalidValue() noexcept
{ {
// The setupapi.h functions return INVALID_HANDLE_VALUE when failing to open a registry key // The setupapi.h functions return INVALID_HANDLE_VALUE when failing to open a registry key
return reinterpret_cast<HKEY>(INVALID_HANDLE_VALUE); return reinterpret_cast<HKEY>(INVALID_HANDLE_VALUE);
} }
static bool close(Type handle) { return RegCloseKey(handle) == ERROR_SUCCESS; } static bool close(Type handle) noexcept { return RegCloseKey(handle) == ERROR_SUCCESS; }
}; };
using DiRegKeyHandle = QUniqueHandle<DiRegKeyHandleTraits>; using DiRegKeyHandle = QUniqueHandle<DiRegKeyHandleTraits>;
@ -145,11 +145,11 @@ using DiRegKeyHandle = QUniqueHandle<DiRegKeyHandleTraits>;
struct DevInfoHandleTraits struct DevInfoHandleTraits
{ {
using Type = HDEVINFO; using Type = HDEVINFO;
static Type invalidValue() static Type invalidValue() noexcept
{ {
return reinterpret_cast<HDEVINFO>(INVALID_HANDLE_VALUE); return reinterpret_cast<HDEVINFO>(INVALID_HANDLE_VALUE);
} }
static bool close(Type handle) { return SetupDiDestroyDeviceInfoList(handle) == TRUE; } static bool close(Type handle) noexcept { return SetupDiDestroyDeviceInfoList(handle) == TRUE; }
}; };
using DevInfoHandle = QUniqueHandle<DevInfoHandleTraits>; using DevInfoHandle = QUniqueHandle<DevInfoHandleTraits>;

View File

@ -843,7 +843,6 @@ QPixmap QWindowsTheme::standardPixmap(StandardPixmap sp, const QSizeF &pixmapSiz
{ {
int resourceId = -1; int resourceId = -1;
SHSTOCKICONID stockId = SIID_INVALID; SHSTOCKICONID stockId = SIID_INVALID;
UINT stockFlags = 0;
LPCTSTR iconName = nullptr; LPCTSTR iconName = nullptr;
switch (sp) { switch (sp) {
case DriveCDIcon: case DriveCDIcon:
@ -867,14 +866,12 @@ QPixmap QWindowsTheme::standardPixmap(StandardPixmap sp, const QSizeF &pixmapSiz
resourceId = 7; resourceId = 7;
break; break;
case FileLinkIcon: case FileLinkIcon:
stockFlags = SHGSI_LINKOVERLAY;
Q_FALLTHROUGH(); Q_FALLTHROUGH();
case FileIcon: case FileIcon:
stockId = SIID_DOCNOASSOC; stockId = SIID_DOCNOASSOC;
resourceId = 1; resourceId = 1;
break; break;
case DirLinkIcon: case DirLinkIcon:
stockFlags = SHGSI_LINKOVERLAY;
Q_FALLTHROUGH(); Q_FALLTHROUGH();
case DirClosedIcon: case DirClosedIcon:
case DirIcon: case DirIcon:
@ -888,7 +885,6 @@ QPixmap QWindowsTheme::standardPixmap(StandardPixmap sp, const QSizeF &pixmapSiz
resourceId = 16; resourceId = 16;
break; break;
case DirLinkOpenIcon: case DirLinkOpenIcon:
stockFlags = SHGSI_LINKOVERLAY;
Q_FALLTHROUGH(); Q_FALLTHROUGH();
case DirOpenIcon: case DirOpenIcon:
stockId = SIID_FOLDEROPEN; stockId = SIID_FOLDEROPEN;
@ -928,18 +924,34 @@ QPixmap QWindowsTheme::standardPixmap(StandardPixmap sp, const QSizeF &pixmapSiz
break; break;
} }
// Even with SHGSI_LINKOVERLAY flag set, loaded Icon with SHDefExtractIcon doesn't have
// any overlay, so we avoid SHGSI_LINKOVERLAY flag and draw it manually (QTBUG-131843)
const auto drawLinkOverlayIconIfNeeded = [](StandardPixmap sp, QPixmap &pixmap, QSizeF pixmapSize) {
if (sp == FileLinkIcon || sp == DirLinkIcon || sp == DirLinkOpenIcon) {
QPainter painter(&pixmap);
const QSizeF linkSize = pixmapSize / (pixmapSize.height() >= 48 ? 3 : 2);
static constexpr auto LinkOverlayIconId = 16769;
const QPixmap link = loadIconFromShell32(LinkOverlayIconId, linkSize.toSize());
const int yPos = pixmap.height() - link.size().height();
painter.drawPixmap(0, yPos, int(linkSize.width()), int(linkSize.height()), link);
}
};
if (stockId != SIID_INVALID) { if (stockId != SIID_INVALID) {
SHSTOCKICONINFO iconInfo; SHSTOCKICONINFO iconInfo;
memset(&iconInfo, 0, sizeof(iconInfo)); memset(&iconInfo, 0, sizeof(iconInfo));
iconInfo.cbSize = sizeof(iconInfo); iconInfo.cbSize = sizeof(iconInfo);
stockFlags |= SHGSI_ICONLOCATION; constexpr UINT stockFlags = SHGSI_ICONLOCATION;
if (SHGetStockIconInfo(stockId, stockFlags, &iconInfo) == S_OK) { if (SHGetStockIconInfo(stockId, stockFlags, &iconInfo) == S_OK) {
const auto iconSize = pixmapSize.width(); const auto iconSize = pixmapSize.width();
HICON icon; HICON icon;
if (SHDefExtractIcon(iconInfo.szPath, iconInfo.iIcon, 0, &icon, nullptr, iconSize) == S_OK) { if (SHDefExtractIcon(iconInfo.szPath, iconInfo.iIcon, 0, &icon, nullptr, iconSize) == S_OK) {
QPixmap pixmap = qt_pixmapFromWinHICON(icon); QPixmap pixmap = qt_pixmapFromWinHICON(icon);
DestroyIcon(icon); DestroyIcon(icon);
return pixmap; if (!pixmap.isNull()) {
drawLinkOverlayIconIfNeeded(sp, pixmap, pixmap.size());
return pixmap;
}
} }
} }
} }
@ -947,11 +959,7 @@ QPixmap QWindowsTheme::standardPixmap(StandardPixmap sp, const QSizeF &pixmapSiz
if (resourceId != -1) { if (resourceId != -1) {
QPixmap pixmap = loadIconFromShell32(resourceId, pixmapSize); QPixmap pixmap = loadIconFromShell32(resourceId, pixmapSize);
if (!pixmap.isNull()) { if (!pixmap.isNull()) {
if (sp == FileLinkIcon || sp == DirLinkIcon || sp == DirLinkOpenIcon) { drawLinkOverlayIconIfNeeded(sp, pixmap, pixmapSize);
QPainter painter(&pixmap);
QPixmap link = loadIconFromShell32(30, pixmapSize);
painter.drawPixmap(0, 0, int(pixmapSize.width()), int(pixmapSize.height()), link);
}
return pixmap; return pixmap;
} }
} }

View File

@ -1405,7 +1405,7 @@ void QWindowsForeignWindow::setParent(const QPlatformWindow *newParentWindow)
qCDebug(lcQpaWindow) << __FUNCTION__ << window() << "newParent=" qCDebug(lcQpaWindow) << __FUNCTION__ << window() << "newParent="
<< newParentWindow << newParent << "oldStyle=" << debugWinStyle(oldStyle); << newParentWindow << newParent << "oldStyle=" << debugWinStyle(oldStyle);
auto updateWindowFlags = [=]{ auto updateWindowFlags = [&]{
// Top level window flags need to be set/cleared manually. // Top level window flags need to be set/cleared manually.
DWORD newStyle = oldStyle; DWORD newStyle = oldStyle;
if (isTopLevel) { if (isTopLevel) {

View File

@ -363,7 +363,7 @@ void QWindowsUiaMainProvider::fillVariantArrayForRelation(QAccessibleInterface*
{ {
Q_ASSERT(accessible); Q_ASSERT(accessible);
typedef QPair<QAccessibleInterface*, QAccessible::Relation> RelationPair; typedef std::pair<QAccessibleInterface*, QAccessible::Relation> RelationPair;
const QList<RelationPair> relationInterfaces = accessible->relations(relation); const QList<RelationPair> relationInterfaces = accessible->relations(relation);
if (relationInterfaces.empty()) if (relationInterfaces.empty())
return; return;