diff --git a/.gitattributes b/.gitattributes index 1385a2ea..5735c8b4 100644 --- a/.gitattributes +++ b/.gitattributes @@ -7,6 +7,9 @@ /packages/debian/01-in-docker.sh eol=lf /packages/debian/rules eol=lf +# files to be processed with Unix utils +/packages/windows/qtbase-5.6.3-redpanda.patch eol=lf + # text files to be packed /packages/appimage/AppRun.sh eol=lf /packages/debian/changelog eol=lf diff --git a/BUILD.md b/BUILD.md index 2f642d65..b64767c2 100644 --- a/BUILD.md +++ b/BUILD.md @@ -4,6 +4,8 @@ # Windows +For Windows 7 or later: + | Library + Toolchain \ Target | x86 | x64 | ARM64 | | ---------------------------- | --- | --- | ----- | | MSYS2 + GNU-based MinGW | ✔️ | ✔️ | ❌ | @@ -19,6 +21,19 @@ Notes for Windows on ARM: - However, ARM64EC will allow users to use their favorite input methods, fancy Qt styles. - With the [ARM32 deprecation in Windows 11 Insider Preview Build 25905](https://blogs.windows.com/windows-insider/2023/07/12/announcing-windows-11-insider-preview-build-25905/), ARM32 support will never be added. +For legacy Windows (NT 5.1 – 6.0): + +| Library + Toolchain \ Target | x86 | x64 | +| ---------------------------- | --- | --- | +| Qt 5.6 from [patched source](packages/windows/qtbase-5.6.3-redpanda.patch) + MinGW | ✔️ | ✔️ | + +Notes for legacy Windows: +- Supported Windows versions: + - Windows XP SP3 or later; + - Windows Server 2003 x64 Edition (a.k.a. Windows XP x64 Edition) SP2 or later. +- Windows 7 x64 or later required as build host. +- Here is [a script](packages/windows/build-qt5.6-mingw-static.sh) for building Qt 5.6 from source alongside official Qt installation (with Qt.io MinGW GCC 8.1.0). + ## MSYS2 Qt Library with MinGW Toolchain (Recommended) Red Panda C++ should work with any MinGW toolchain from MSYS2, including GCCs and Clangs in three GNU-based environments (MINGW32, MINGW64 and UCRT64), and Clangs in three LLVM-based environments (CLANG32, CLANG64 and CLANGARM64; see also [MSYS2’s document](https://www.msys2.org/docs/environments/)), while the following toolchains are frequently tested: diff --git a/BUILD_cn.md b/BUILD_cn.md index 00c638b9..1dc2f851 100644 --- a/BUILD_cn.md +++ b/BUILD_cn.md @@ -4,6 +4,8 @@ # Windows +适用于 Windows 7 或更高版本: + | 库 + 工具链 \ 目标 | x86 | x64 | ARM64 | | ------------------ | --- | --- | ----- | | MSYS2 + 基于 GNU 的 MinGW | ✔️ | ✔️ | ❌ | @@ -19,6 +21,19 @@ - 但是 ARM64EC 可以支持用户习惯的输入法和喜欢的 Qt 样式。 - 随着 [Windows 11 Insider Preview Build 25905 弃用 ARM32](https://blogs.windows.com/windows-insider/2023/07/12/announcing-windows-11-insider-preview-build-25905/),小熊猫 C++ 今后也不会添加 ARM32 支持了。 +适用于旧版 Windows(NT 5.1 – 6.0): + +| 库 + 工具链 \ 目标 | x86 | x64 | +| ------------------ | --- | --- | +| 从[打过补丁的源代码](packages/windows/qtbase-5.6.3-redpanda.patch)构建的 Qt 5.6 + MinGW | ✔️ | ✔️ | + +关于旧版 Windows 的注记: +- 支持的 Windows 版本: + - Windows XP SP3 或更高版本; + - Windows Server 2003 x64 Edition(也叫 Windows XP x64 Edition)SP2 或更高版本。 +- 构建环境需要 Windows 7 x64 或更高版本。 +- 从源代码构建 Qt 5.6 并与官方 Qt 安装共存可参考[这个脚本](packages/windows/build-qt5.6-mingw-static.sh)(使用 Qt.io MinGW GCC 8.1.0)。 + ## MSYS2 的 Qt 库 + MinGW 工具链(推荐) 小熊猫 C++ 应该能在 MSYS2 的 MinGW 工具链上构建,包括 3 个基于 GNU 的环境(MINGW32、MINGW64、UCRT64)中的 GCC 和 Clang,以及 3 个基于 LLVM 的环境(CLANG32、CLANG64、CLANGARM64)中的 Clang,关于环境的详情可参考 [MSYS2 的文档](https://www.msys2.org/docs/environments/)。以下几个工具链测试较充分: diff --git a/RedPandaIDE/RedPandaIDE.pro b/RedPandaIDE/RedPandaIDE.pro index 7cb815a3..fc00c080 100644 --- a/RedPandaIDE/RedPandaIDE.pro +++ b/RedPandaIDE/RedPandaIDE.pro @@ -1,6 +1,7 @@ QT += core gui printsupport network svg xml widgets -CONFIG += c++17 +# without `c++14` old versions of qmake will explicitly set `-std=gnu++98` +CONFIG += c++14 c++17 CONFIG += nokey # uncomment the following line to enable vcs (git) support @@ -44,9 +45,10 @@ isEmpty(LIBEXECDIR) { LIBEXECDIR = $${PREFIX}/libexec } -# windows 7 is the minimum windows version win32: { -DEFINES += _WIN32_WINNT=0x0601 + DEFINES += _WIN32_WINNT=0x0501 + LIBS += -lpsapi # GetModuleFileNameEx, GetProcessMemoryInfo + LIBS += -lshlwapi # SHDeleteKey } DEFINES += PREFIX=\\\"$${PREFIX}\\\" diff --git a/RedPandaIDE/compiler/executablerunner.h b/RedPandaIDE/compiler/executablerunner.h index c20ce582..17128b05 100644 --- a/RedPandaIDE/compiler/executablerunner.h +++ b/RedPandaIDE/compiler/executablerunner.h @@ -20,6 +20,7 @@ #include "runner.h" #include #include +#include class ExecutableRunner : public Runner { diff --git a/RedPandaIDE/editor.cpp b/RedPandaIDE/editor.cpp index a6bc821e..340677ae 100644 --- a/RedPandaIDE/editor.cpp +++ b/RedPandaIDE/editor.cpp @@ -1888,7 +1888,7 @@ void Editor::onAutoBackupTimer() if (mBackupTime>lastModifyTime()) return; QDateTime current=QDateTime::currentDateTime(); - if (current.toSecsSinceEpoch()-lastModifyTime().toSecsSinceEpoch()<=3) + if (lastModifyTime().secsTo(current) <= 3) return; saveAutoBackup(); } diff --git a/RedPandaIDE/main.cpp b/RedPandaIDE/main.cpp index dda8dc94..9fe39af9 100644 --- a/RedPandaIDE/main.cpp +++ b/RedPandaIDE/main.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include "common.h" #include "colorscheme.h" #include "iconsmanager.h" @@ -58,7 +59,13 @@ public: bool nativeEventFilter(const QByteArray &eventType, void *message, long *result) override; }; -#define WM_USER_OPEN_FILE (WM_USER+1) +#ifndef WM_DPICHANGED +# define WM_DPICHANGED 0x02e0 +#endif + +#define WM_APP_OPEN_FILE (WM_APP + 6736 /* “OPEN” on dial pad */) +static_assert(WM_APP_OPEN_FILE < 0xc000); + HWND prevAppInstance = NULL; BOOL CALLBACK GetPreviousInstanceCallback(HWND hwnd, LPARAM param){ BOOL result = TRUE; @@ -144,7 +151,7 @@ bool WindowLogoutEventFilter::nativeEventFilter(const QByteArray & /*eventType*/ } break; } - case WM_USER_OPEN_FILE: { + case WM_APP_OPEN_FILE: { QSharedMemory sharedMemory("RedPandaCpp/openfiles"); if (sharedMemory.attach()) { QBuffer buffer; @@ -184,7 +191,7 @@ bool sendFilesToInstance() { const char *from = buffer.data().data(); memcpy(to, from, qMin(sharedMemory.size(), size)); sharedMemory.unlock(); - SendMessage(prevInstance,WM_USER_OPEN_FILE,0,0); + SendMessage(prevInstance,WM_APP_OPEN_FILE,0,0); return true; } } @@ -270,7 +277,7 @@ int main(int argc, char *argv[]) app.setAttribute(Qt::AA_UseHighDpiPixmaps); - QFile tempFile(QDir::tempPath()+QDir::separator()+"RedPandaDevCppStartUp.lock"); + QLockFile lockFile(QDir::tempPath()+QDir::separator()+"RedPandaDevCppStartUp.lock"); { bool firstRun; QString settingFilename = getSettingFilename(QString(), firstRun); @@ -288,7 +295,7 @@ int main(int argc, char *argv[]) if (openInSingleInstance) { int openCount = 0; while (true) { - if (tempFile.open(QFile::NewOnly)) + if (lockFile.tryLock()) break; QThread::msleep(100); openCount++; @@ -299,7 +306,7 @@ int main(int argc, char *argv[]) if (app.arguments().length()>=2 && openCount<100) { #ifdef Q_OS_WIN if (sendFilesToInstance()) { - tempFile.remove(); + lockFile.unlock(); return 0; } #endif @@ -314,7 +321,7 @@ int main(int argc, char *argv[]) QDir::setCurrent(QStandardPaths::standardLocations(QStandardPaths::DocumentsLocation)[0]); } if (settingFilename.isEmpty()) { - tempFile.remove(); + lockFile.unlock(); return -1; } QString language; @@ -433,9 +440,8 @@ int main(int argc, char *argv[]) WindowLogoutEventFilter filter; app.installNativeEventFilter(&filter); #endif - if (tempFile.isOpen()) { - tempFile.close(); - tempFile.remove(); + if (lockFile.isLocked()) { + lockFile.unlock(); } int retCode = app.exec(); @@ -448,7 +454,7 @@ int main(int argc, char *argv[]) } return retCode; } catch (BaseError e) { - tempFile.remove(); + lockFile.unlock(); QMessageBox::critical(nullptr,QApplication::tr("Error"),e.reason()); return -1; } diff --git a/RedPandaIDE/mainwindow.cpp b/RedPandaIDE/mainwindow.cpp index 4329e25e..c79a05c9 100644 --- a/RedPandaIDE/mainwindow.cpp +++ b/RedPandaIDE/mainwindow.cpp @@ -4505,7 +4505,12 @@ void MainWindow::onFilesViewCreateFile() fileName = QString("untitled%1").arg(count)+suffix; } QFile file(dir.filePath(fileName)); +#if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0) file.open(QFile::NewOnly); +#else + // workaround: try create but do not truncate + file.open(QFile::ReadWrite); +#endif QModelIndex newIndex = mFileSystemModel.index(fileName); ui->treeFiles->setCurrentIndex(newIndex); } diff --git a/RedPandaIDE/parser/cpppreprocessor.cpp b/RedPandaIDE/parser/cpppreprocessor.cpp index c02aef9a..1a1ff350 100644 --- a/RedPandaIDE/parser/cpppreprocessor.cpp +++ b/RedPandaIDE/parser/cpppreprocessor.cpp @@ -326,7 +326,7 @@ QString CppPreprocessor::getNextPreprocessor() QString result; for (int i=preProcFrom;i<=preProcTo;i++) { if (mBuffer[i].endsWith('\\')) { - result+=mBuffer[i].leftRef(mBuffer[i].size()-1)+' '; + result+=mBuffer[i].left(mBuffer[i].size()-1)+' '; } else { result+=mBuffer[i]+' '; } diff --git a/RedPandaIDE/parser/parserutils.h b/RedPandaIDE/parser/parserutils.h index bf2b21df..3247996b 100644 --- a/RedPandaIDE/parser/parserutils.h +++ b/RedPandaIDE/parser/parserutils.h @@ -21,6 +21,7 @@ #include #include #include +#include using GetFileStreamCallBack = std::function; diff --git a/RedPandaIDE/settingsdialog/environmentfileassociationwidget.cpp b/RedPandaIDE/settingsdialog/environmentfileassociationwidget.cpp index fcdb76de..1c902b68 100644 --- a/RedPandaIDE/settingsdialog/environmentfileassociationwidget.cpp +++ b/RedPandaIDE/settingsdialog/environmentfileassociationwidget.cpp @@ -21,6 +21,7 @@ #include #include +#include EnvironmentFileAssociationWidget::EnvironmentFileAssociationWidget(const QString& name, const QString& group, QWidget *parent) : SettingsWidget(name,group,parent), @@ -156,33 +157,33 @@ bool FileAssociationModel::checkAssociation(const QString &extension, const QStr HKEY key; LONG result; - result = RegOpenKeyExA(HKEY_CLASSES_ROOT,extension.toLocal8Bit(),0,KEY_READ,&key); + result = RegOpenKeyExW(HKEY_CLASSES_ROOT,extension.toStdWString().c_str(),0,KEY_READ,&key); RegCloseKey(key); if (result != ERROR_SUCCESS ) return false; - result = RegOpenKeyExA(HKEY_CLASSES_ROOT,filetype.toLocal8Bit(),0,KEY_READ,&key); + result = RegOpenKeyExW(HKEY_CLASSES_ROOT,filetype.toStdWString().c_str(),0,KEY_READ,&key); RegCloseKey(key); if (result != ERROR_SUCCESS ) return false; QString keyString = QString("%1\\Shell\\%2\\Command").arg(filetype).arg(verb); QString value1,value2; - if (!readRegistry(HKEY_CLASSES_ROOT,keyString.toLocal8Bit(),"",value1)) + if (!readRegistry(HKEY_CLASSES_ROOT, keyString, "", value1)) return false; - if (!readRegistry(HKEY_CLASSES_ROOT,extension.toLocal8Bit(),"",value2)) + if (!readRegistry(HKEY_CLASSES_ROOT, extension, "", value2)) return false; return (value2 == filetype) && (value1.compare(serverApp,PATH_SENSITIVITY)==0); } -bool writeRegistry(HKEY parentKey, const QByteArray& subKey, const QByteArray& value) { +bool writeRegistry(HKEY parentKey, const QString& subKey, const QString& value) { DWORD disposition; HKEY key; - LONG result = RegCreateKeyExA( + LONG result = RegCreateKeyExW( parentKey, - subKey, + subKey.toStdWString().c_str(), 0, NULL, REG_OPTION_NON_VOLATILE, @@ -190,24 +191,23 @@ bool writeRegistry(HKEY parentKey, const QByteArray& subKey, const QByteArray& v NULL, &key, &disposition); - RegCloseKey(key); if (result != ERROR_SUCCESS ) { + RegCloseKey(key); return false; } - result = RegSetKeyValueA( - HKEY_CLASSES_ROOT, - subKey, - "", + result = RegSetValueExW( + key, + L"", + 0, REG_SZ, - (const BYTE*)value.data(), - value.length()+1); + (const BYTE*)value.toStdWString().c_str(), + (value.length() + 1) * sizeof(wchar_t)); + RegCloseKey(key); return result == ERROR_SUCCESS; } bool FileAssociationModel::registerAssociation(const QString &extension, const QString &filetype) { - if (!writeRegistry(HKEY_CLASSES_ROOT, - extension.toLocal8Bit(), - filetype.toLocal8Bit())){ + if (!writeRegistry(HKEY_CLASSES_ROOT, extension, filetype)){ return false; } return true; @@ -217,12 +217,12 @@ bool FileAssociationModel::unregisterAssociation(const QString &extension) { LONG result; HKEY key; - result = RegOpenKeyExA(HKEY_CLASSES_ROOT,extension.toLocal8Bit(),0,KEY_READ,&key); + result = RegOpenKeyExW(HKEY_CLASSES_ROOT, extension.toStdWString().c_str(), 0, KEY_READ, &key); if (result != ERROR_SUCCESS ) return true; RegCloseKey(key); - result = RegDeleteTreeA(HKEY_CLASSES_ROOT,extension.toLocal8Bit()); + result = SHDeleteKeyW(HKEY_CLASSES_ROOT, extension.toStdWString().c_str()); return result == ERROR_SUCCESS; } @@ -231,33 +231,27 @@ bool FileAssociationModel::unregisterFileType(const QString &fileType) { LONG result; HKEY key; - result = RegOpenKeyExA(HKEY_CLASSES_ROOT,fileType.toLocal8Bit(),0,KEY_READ,&key); + result = RegOpenKeyExW(HKEY_CLASSES_ROOT, fileType.toStdWString().c_str(), 0, KEY_READ, &key); if (result != ERROR_SUCCESS ) return true; RegCloseKey(key); - result = RegDeleteTreeA(HKEY_CLASSES_ROOT,fileType.toLocal8Bit()); + result = SHDeleteKeyW(HKEY_CLASSES_ROOT, fileType.toStdWString().c_str()); return result == ERROR_SUCCESS; } bool FileAssociationModel::registerFileType(const QString &filetype, const QString &description, const QString &verb, const QString &serverApp, int icon) { - if (!writeRegistry(HKEY_CLASSES_ROOT, - filetype.toLocal8Bit(), - description.toLocal8Bit())) + if (!writeRegistry(HKEY_CLASSES_ROOT, filetype, description)) return false; QString keyString = QString("%1\\DefaultIcon").arg(filetype); QString value = QString("%1,%2").arg(serverApp).arg(icon); - if (!writeRegistry(HKEY_CLASSES_ROOT, - keyString.toLocal8Bit(), - value.toLocal8Bit())) + if (!writeRegistry(HKEY_CLASSES_ROOT, keyString, value)) return false; keyString = QString("%1\\Shell\\%2\\Command").arg(filetype).arg(verb); value = serverApp+" \"%1\""; - if (!writeRegistry(HKEY_CLASSES_ROOT, - keyString.toLocal8Bit(), - value.toLocal8Bit())) + if (!writeRegistry(HKEY_CLASSES_ROOT, keyString, value)) return false; return true; } diff --git a/RedPandaIDE/settingsdialog/environmentfileassociationwidget.h b/RedPandaIDE/settingsdialog/environmentfileassociationwidget.h index 3e5f4a52..a008d7c5 100644 --- a/RedPandaIDE/settingsdialog/environmentfileassociationwidget.h +++ b/RedPandaIDE/settingsdialog/environmentfileassociationwidget.h @@ -19,6 +19,7 @@ #include #include +#include #include "settingswidget.h" namespace Ui { diff --git a/RedPandaIDE/utils.cpp b/RedPandaIDE/utils.cpp index 04913f86..9287f674 100644 --- a/RedPandaIDE/utils.cpp +++ b/RedPandaIDE/utils.cpp @@ -389,9 +389,9 @@ bool isGreenEdition() if (!gIsGreenEditionInited) { QString keyString = QString("Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\RedPanda-C++"); QString value; - if (!readRegistry(HKEY_LOCAL_MACHINE,keyString.toLocal8Bit(),"UninstallString",value)) { + if (!readRegistry(HKEY_LOCAL_MACHINE, keyString, "UninstallString", value)) { keyString = "SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\RedPanda-C++"; - if (!readRegistry(HKEY_LOCAL_MACHINE,keyString.toLocal8Bit(),"UninstallString",value)) { + if (!readRegistry(HKEY_LOCAL_MACHINE, keyString, "UninstallString", value)) { value=""; } } @@ -465,27 +465,30 @@ void executeFile(const QString &fileName, const QString ¶ms, const QString & } #ifdef Q_OS_WIN -bool readRegistry(HKEY key,const QByteArray& subKey, const QByteArray& name, QString& value) { - DWORD dataSize; +bool readRegistry(HKEY key,const QString& subKey, const QString& name, QString& value) { LONG result; - result = RegGetValueA(key,subKey, - name, RRF_RT_REG_SZ | RRF_RT_REG_MULTI_SZ, - NULL, - NULL, - &dataSize); - if (result!=ERROR_SUCCESS) + HKEY hkey; + result = RegOpenKeyExW(key, subKey.toStdWString().c_str(), 0, KEY_READ, &hkey); + if (result != ERROR_SUCCESS) return false; - char * buffer = new char[dataSize+10]; - result = RegGetValueA(key,subKey, - name, RRF_RT_REG_SZ | RRF_RT_REG_MULTI_SZ, - NULL, - buffer, - &dataSize); - if (result!=ERROR_SUCCESS) { + + DWORD dataType; + DWORD dataSize; + result = RegQueryValueExW(hkey, name.toStdWString().c_str(), NULL, &dataType, NULL, &dataSize); + if (result != ERROR_SUCCESS || (dataType != REG_SZ && dataType != REG_MULTI_SZ)) { + RegCloseKey(hkey); + return false; + } + + wchar_t * buffer = new wchar_t[dataSize / sizeof(wchar_t) + 10]; + result = RegQueryValueExW(hkey, name.toStdWString().c_str(), NULL, &dataType, (LPBYTE)buffer, &dataSize); + RegCloseKey(hkey); + if (result != ERROR_SUCCESS) { delete[] buffer; return false; } - value=QString::fromLocal8Bit(buffer); + + value = QString::fromWCharArray(buffer); delete [] buffer; return true; } diff --git a/RedPandaIDE/utils.h b/RedPandaIDE/utils.h index 6e68c276..7ffa511b 100644 --- a/RedPandaIDE/utils.h +++ b/RedPandaIDE/utils.h @@ -145,7 +145,7 @@ void executeFile(const QString& fileName, bool isGreenEdition(); #ifdef Q_OS_WIN -bool readRegistry(HKEY key,const QByteArray& subKey, const QByteArray& name, QString& value); +bool readRegistry(HKEY key, const QString& subKey, const QString& name, QString& value); #endif qulonglong stringToHex(const QString& str, bool &isOk); diff --git a/libs/qsynedit/qsynedit.pro b/libs/qsynedit/qsynedit.pro index bf1dbf07..8e5b2fe3 100644 --- a/libs/qsynedit/qsynedit.pro +++ b/libs/qsynedit/qsynedit.pro @@ -2,7 +2,8 @@ TEMPLATE = lib QT += core gui greaterThan(QT_MAJOR_VERSION, 4): QT += widgets -CONFIG += c++17 +# without `c++14` old versions of qmake will explicitly set `-std=gnu++98` +CONFIG += c++14 c++17 CONFIG += nokey CONFIG += staticlib contains(QMAKE_HOST.arch, x86_64):{ @@ -15,7 +16,7 @@ contains(QMAKE_HOST.arch, x86_64):{ win32: { -DEFINES += _WIN32_WINNT=0x0601 + DEFINES += _WIN32_WINNT=0x0501 } gcc { diff --git a/libs/qsynedit/qsynedit/miscprocs.h b/libs/qsynedit/qsynedit/miscprocs.h index 09eedbee..98071b73 100644 --- a/libs/qsynedit/qsynedit/miscprocs.h +++ b/libs/qsynedit/qsynedit/miscprocs.h @@ -26,6 +26,7 @@ #include #include #include +#include //#include //#include diff --git a/libs/redpanda_qt_utils/redpanda_qt_utils.pro b/libs/redpanda_qt_utils/redpanda_qt_utils.pro index ca594ba2..76171735 100644 --- a/libs/redpanda_qt_utils/redpanda_qt_utils.pro +++ b/libs/redpanda_qt_utils/redpanda_qt_utils.pro @@ -3,12 +3,13 @@ QT += core gui greaterThan(QT_MAJOR_VERSION, 4): QT += widgets -CONFIG += c++17 +# without `c++14` old versions of qmake will explicitly set `-std=gnu++98` +CONFIG += c++14 c++17 CONFIG += nokey CONFIG += staticlib win32: { -DEFINES += _WIN32_WINNT=0x0601 + DEFINES += _WIN32_WINNT=0x0501 } gcc { diff --git a/packages/windows/build-qt5.6-mingw-static.sh b/packages/windows/build-qt5.6-mingw-static.sh new file mode 100644 index 00000000..40df7c1d --- /dev/null +++ b/packages/windows/build-qt5.6-mingw-static.sh @@ -0,0 +1,113 @@ +# for Git Bash + +set -xe + +QT_CONFIGURE_DEBUG_OR_RELEASE="-release" +OFFICIAL_QT_DIRECTORY="/c/Qt" +QT_INSTALL_PREFIX="/c/Qt/5.6.3" + +qt-module-directory() { + moduleName="$1" + echo "qt$moduleName-opensource-src-5.6.3" +} + +prepare-qt-base-source() { + moduleDirectory="$(qt-module-directory base)" + fileName="$moduleDirectory.tar.xz" + + if ! [[ -d "$moduleDirectory" ]] ; then + patchFileName="qtbase-5.6.3-redpanda.patch" + if ! [[ -f "$patchFileName" ]] ; then + echo -n "Patch file not found. Please copy it to this directory and press enter to continue..." + read -r + fi + if ! [[ -f "$fileName" ]] ; then + downloadUrl="https://download.qt.io/new_archive/qt/5.6/5.6.3/submodules/$fileName" + curl -L -o "$fileName" "$downloadUrl" + fi + tar xf "$fileName" + tar xf "$fileName" "$moduleDirectory/configure.exe" # workaround for MSYS2 tar bug: https://github.com/msys2/MSYS2-packages/issues/4103 + pushd "$moduleDirectory" + patch --forward --strip=1 --input="../$patchFileName" + popd + fi +} + +prepare-qt-module-source() { + moduleName="$1" + moduleDirectory="$(qt-module-directory $moduleName)" + fileName="$moduleDirectory.tar.xz" + + if ! [[ -d "$moduleDirectory" ]] ; then + if ! [[ -f "$fileName" ]] ; then + downloadUrl="https://download.qt.io/new_archive/qt/5.6/5.6.3/submodules/$fileName" + curl -L -o "$fileName" "$downloadUrl" + fi + tar xf "$fileName" + fi +} + +prepare-qt-sources() { + prepare-qt-base-source + prepare-qt-module-source svg + prepare-qt-module-source tools +} + +build-qt-base() { + configuration="$1" + + buildDir="build-qtbase-$configuration" + mkdir -p "$buildDir" + pushd "$buildDir" + + prefix="$QT_INSTALL_PREFIX/$configuration" + "../$(qt-module-directory base)/configure.bat" \ + -prefix $prefix $QT_CONFIGURE_DEBUG_OR_RELEASE \ + -opensource -confirm-license \ + -no-use-gold-linker -static -static-runtime -platform win32-g++ -target xp \ + -opengl desktop -no-angle -iconv -gnu-iconv -no-icu -qt-zlib -qt-pcre -qt-libpng -qt-libjpeg -qt-freetype -no-fontconfig -qt-harfbuzz -no-ssl -no-openssl \ + -nomake examples -nomake tests -nomake tools + mingw32-make "-j$(nproc)" + mingw32-make install + export PATH="$prefix/bin:$PATH" + + popd +} + +build-qt-module() { + configuration="$1" + moduleName="$2" + + buildDir="build-qt$moduleName-$configuration" + mkdir -p $buildDir + pushd $buildDir + + qmake "../$(qt-module-directory $moduleName)" + mingw32-make "-j$(nproc)" + mingw32-make install + + popd +} + +build-qt() { + configuration="$1" + + build-qt-base $configuration + build-qt-module $configuration svg + build-qt-module $configuration tools +} + +main() { + basePath="$PATH" + prepare-qt-sources + + ## 32-bit + export PATH="$OFFICIAL_QT_DIRECTORY/Tools/mingw810_32/bin:$basePath" + build-qt mingw81_32-redpanda + + ## 64-bit + export PATH="$OFFICIAL_QT_DIRECTORY/Tools/mingw810_64/bin:$basePath" + build-qt mingw81_64-redpanda +} + +main diff --git a/packages/windows/qtbase-5.6.3-redpanda.patch b/packages/windows/qtbase-5.6.3-redpanda.patch new file mode 100644 index 00000000..a21a9da8 --- /dev/null +++ b/packages/windows/qtbase-5.6.3-redpanda.patch @@ -0,0 +1,856 @@ +diff --unified --recursive --text qtbase-opensource-src-5.6.3.orig/src/corelib/global/qflags.h qtbase-opensource-src-5.6.3/src/corelib/global/qflags.h +--- qtbase-opensource-src-5.6.3.orig/src/corelib/global/qflags.h 2017-09-06 20:13:54.000000000 +0800 ++++ qtbase-opensource-src-5.6.3/src/corelib/global/qflags.h 2023-10-17 20:31:37.670315600 +0800 +@@ -139,6 +139,11 @@ + Q_DECL_CONSTEXPR inline bool operator!() const Q_DECL_NOTHROW { return !i; } + + Q_DECL_CONSTEXPR inline bool testFlag(Enum f) const Q_DECL_NOTHROW { return (i & Int(f)) == Int(f) && (Int(f) != 0 || i == Int(f) ); } ++ Q_DECL_RELAXED_CONSTEXPR inline QFlags &setFlag(Enum f, bool on = true) Q_DECL_NOTHROW ++ { ++ return on ? (*this |= f) : (*this &= ~Int(f)); ++ } ++ + private: + #ifdef Q_COMPILER_INITIALIZER_LISTS + Q_DECL_CONSTEXPR static inline Int initializer_list_helper(typename std::initializer_list::const_iterator it, +diff --unified --recursive --text qtbase-opensource-src-5.6.3.orig/src/corelib/global/qglobal.h qtbase-opensource-src-5.6.3/src/corelib/global/qglobal.h +--- qtbase-opensource-src-5.6.3.orig/src/corelib/global/qglobal.h 2017-09-06 20:13:54.000000000 +0800 ++++ qtbase-opensource-src-5.6.3/src/corelib/global/qglobal.h 2023-10-17 14:38:05.801809800 +0800 +@@ -67,6 +67,9 @@ + # define QT_NO_UNSHARABLE_CONTAINERS + #endif + ++// Red Panda C++: workaround. ++#define QT_CONFIG(feature) QT_SUPPORTS(feature) ++ + /* These two macros makes it possible to turn the builtin line expander into a + * string literal. */ + #define QT_STRINGIFY2(x) #x +@@ -1054,6 +1057,53 @@ + + #endif // QT_NO_TRANSLATION + ++template ++struct QNonConstOverload ++{ ++ template ++ Q_DECL_CONSTEXPR auto operator()(R (T::*ptr)(Args...)) const Q_DECL_NOTHROW -> decltype(ptr) ++ { return ptr; } ++ ++ template ++ static Q_DECL_CONSTEXPR auto of(R (T::*ptr)(Args...)) Q_DECL_NOTHROW -> decltype(ptr) ++ { return ptr; } ++}; ++ ++template ++struct QConstOverload ++{ ++ template ++ Q_DECL_CONSTEXPR auto operator()(R (T::*ptr)(Args...) const) const Q_DECL_NOTHROW -> decltype(ptr) ++ { return ptr; } ++ ++ template ++ static Q_DECL_CONSTEXPR auto of(R (T::*ptr)(Args...) const) Q_DECL_NOTHROW -> decltype(ptr) ++ { return ptr; } ++}; ++ ++template ++struct QOverload : QConstOverload, QNonConstOverload ++{ ++ using QConstOverload::of; ++ using QConstOverload::operator(); ++ using QNonConstOverload::of; ++ using QNonConstOverload::operator(); ++ ++ template ++ Q_DECL_CONSTEXPR auto operator()(R (*ptr)(Args...)) const Q_DECL_NOTHROW -> decltype(ptr) ++ { return ptr; } ++ ++ template ++ static Q_DECL_CONSTEXPR auto of(R (*ptr)(Args...)) Q_DECL_NOTHROW -> decltype(ptr) ++ { return ptr; } ++}; ++ ++#if defined(__cpp_variable_templates) && __cpp_variable_templates >= 201304 // C++14 ++template Q_CONSTEXPR Q_DECL_UNUSED QOverload qOverload = {}; ++template Q_CONSTEXPR Q_DECL_UNUSED QConstOverload qConstOverload = {}; ++template Q_CONSTEXPR Q_DECL_UNUSED QNonConstOverload qNonConstOverload = {}; ++#endif ++ + /* + When RTTI is not available, define this macro to force any uses of + dynamic_cast to cause a compile failure. +diff --unified --recursive --text qtbase-opensource-src-5.6.3.orig/src/corelib/global/qsystemdetection.h qtbase-opensource-src-5.6.3/src/corelib/global/qsystemdetection.h +--- qtbase-opensource-src-5.6.3.orig/src/corelib/global/qsystemdetection.h 2017-09-06 20:13:54.000000000 +0800 ++++ qtbase-opensource-src-5.6.3/src/corelib/global/qsystemdetection.h 2023-10-17 22:26:59.822029100 +0800 +@@ -184,6 +184,7 @@ + #endif + + #if defined(Q_OS_WIN32) || defined(Q_OS_WIN64) || defined(Q_OS_WINCE) || defined(Q_OS_WINRT) ++# define Q_OS_WINDOWS + # define Q_OS_WIN + #endif + +diff --unified --recursive --text qtbase-opensource-src-5.6.3.orig/src/corelib/io/qdir.cpp qtbase-opensource-src-5.6.3/src/corelib/io/qdir.cpp +--- qtbase-opensource-src-5.6.3.orig/src/corelib/io/qdir.cpp 2017-09-06 20:13:54.000000000 +0800 ++++ qtbase-opensource-src-5.6.3/src/corelib/io/qdir.cpp 2023-10-17 14:38:05.801809800 +0800 +@@ -1812,6 +1812,13 @@ + return QFile::exists(filePath(name)); + } + ++bool QDir::isEmpty(Filters filters) const ++{ ++ const auto d = d_ptr.constData(); ++ QDirIterator it(d->dirEntry.filePath(), d->nameFilters, filters); ++ return !it.hasNext(); ++} ++ + /*! + Returns a list of the root directories on this system. + +diff --unified --recursive --text qtbase-opensource-src-5.6.3.orig/src/corelib/io/qdir.h qtbase-opensource-src-5.6.3/src/corelib/io/qdir.h +--- qtbase-opensource-src-5.6.3.orig/src/corelib/io/qdir.h 2017-09-06 20:13:54.000000000 +0800 ++++ qtbase-opensource-src-5.6.3/src/corelib/io/qdir.h 2023-10-17 14:38:05.801809800 +0800 +@@ -138,6 +138,8 @@ + void setSorting(SortFlags sort); + + uint count() const; ++ bool isEmpty(Filters filters = Filters(AllEntries | NoDotAndDotDot)) const; ++ + QString operator[](int) const; + + static QStringList nameFiltersFromString(const QString &nameFilter); +diff --unified --recursive --text qtbase-opensource-src-5.6.3.orig/src/corelib/io/qprocess.cpp qtbase-opensource-src-5.6.3/src/corelib/io/qprocess.cpp +--- qtbase-opensource-src-5.6.3.orig/src/corelib/io/qprocess.cpp 2017-09-06 20:13:54.000000000 +0800 ++++ qtbase-opensource-src-5.6.3/src/corelib/io/qprocess.cpp 2023-10-18 09:11:02.546767400 +0800 +@@ -1535,6 +1535,18 @@ + d->nativeArguments = arguments; + } + ++QProcess::CreateProcessArgumentModifier QProcess::createProcessArgumentsModifier() const ++{ ++ Q_D(const QProcess); ++ return d->modifyCreateProcessArgs; ++} ++ ++void QProcess::setCreateProcessArgumentsModifier(CreateProcessArgumentModifier modifier) ++{ ++ Q_D(QProcess); ++ d->modifyCreateProcessArgs = modifier; ++} ++ + #endif + + /*! +@@ -2124,6 +2136,20 @@ + d->start(mode); + } + ++bool QProcess::startDetached(qint64 *pid) ++{ ++ Q_D(QProcess); ++ if (d->processState != NotRunning) { ++ qWarning("QProcess::startDetached: Process is already running"); ++ return false; ++ } ++ if (d->program.isEmpty()) { ++ d->setErrorAndEmit(QProcess::FailedToStart, tr("No program defined")); ++ return false; ++ } ++ return d->startDetached(pid); ++} ++ + /*! + Starts the program set by setProgram() with arguments set by setArguments(). + The OpenMode is set to \a mode. +diff --unified --recursive --text qtbase-opensource-src-5.6.3.orig/src/corelib/io/qprocess.h qtbase-opensource-src-5.6.3/src/corelib/io/qprocess.h +--- qtbase-opensource-src-5.6.3.orig/src/corelib/io/qprocess.h 2017-09-06 20:13:54.000000000 +0800 ++++ qtbase-opensource-src-5.6.3/src/corelib/io/qprocess.h 2023-10-18 09:09:01.053605200 +0800 +@@ -38,6 +38,8 @@ + #include + #include + ++#include ++ + QT_BEGIN_NAMESPACE + + +@@ -48,6 +50,8 @@ + #else + QT_END_NAMESPACE + typedef struct _PROCESS_INFORMATION *Q_PID; ++typedef struct _SECURITY_ATTRIBUTES Q_SECURITY_ATTRIBUTES; ++typedef struct _STARTUPINFOW Q_STARTUPINFO; + QT_BEGIN_NAMESPACE + #endif + +@@ -151,6 +155,7 @@ + void start(const QString &command, OpenMode mode = ReadWrite); + #endif + void start(OpenMode mode = ReadWrite); ++ bool startDetached(qint64 *pid = nullptr); + bool open(OpenMode mode = ReadWrite) Q_DECL_OVERRIDE; + + QString program() const; +@@ -180,6 +185,22 @@ + #if defined(Q_OS_WIN) + QString nativeArguments() const; + void setNativeArguments(const QString &arguments); ++ struct CreateProcessArguments ++ { ++ const wchar_t *applicationName; ++ wchar_t *arguments; ++ Q_SECURITY_ATTRIBUTES *processAttributes; ++ Q_SECURITY_ATTRIBUTES *threadAttributes; ++ bool inheritHandles; ++ unsigned long flags; ++ void *environment; ++ const wchar_t *currentDirectory; ++ Q_STARTUPINFO *startupInfo; ++ Q_PID processInformation; ++ }; ++ typedef std::function CreateProcessArgumentModifier; ++ CreateProcessArgumentModifier createProcessArgumentsModifier() const; ++ void setCreateProcessArgumentsModifier(CreateProcessArgumentModifier modifier); + #endif + + QString workingDirectory() const; +diff --unified --recursive --text qtbase-opensource-src-5.6.3.orig/src/corelib/io/qprocess_p.h qtbase-opensource-src-5.6.3/src/corelib/io/qprocess_p.h +--- qtbase-opensource-src-5.6.3.orig/src/corelib/io/qprocess_p.h 2017-09-06 20:13:54.000000000 +0800 ++++ qtbase-opensource-src-5.6.3/src/corelib/io/qprocess_p.h 2023-10-17 14:38:05.822849000 +0800 +@@ -326,6 +326,7 @@ + QStringList arguments; + #if defined(Q_OS_WIN) + QString nativeArguments; ++ QProcess::CreateProcessArgumentModifier modifyCreateProcessArgs; + #endif + QProcessEnvironment environment; + +@@ -355,6 +356,7 @@ + bool waitForDeadChild(); + #endif + #ifdef Q_OS_WIN ++ bool callCreateProcess(QProcess::CreateProcessArguments *cpargs); + bool drainOutputPipes(); + void flushPipeWriter(); + qint64 pipeWriterBytesToWrite() const; +@@ -363,6 +365,8 @@ + static bool startDetached(const QString &program, const QStringList &arguments, const QString &workingDirectory = QString(), + qint64 *pid = 0); + ++ bool startDetached(qint64 *pPid); ++ + int exitCode; + QProcess::ExitStatus exitStatus; + bool crashed; +diff --unified --recursive --text qtbase-opensource-src-5.6.3.orig/src/corelib/io/qprocess_win.cpp qtbase-opensource-src-5.6.3/src/corelib/io/qprocess_win.cpp +--- qtbase-opensource-src-5.6.3.orig/src/corelib/io/qprocess_win.cpp 2017-09-06 20:13:54.000000000 +0800 ++++ qtbase-opensource-src-5.6.3/src/corelib/io/qprocess_win.cpp 2023-10-18 09:15:27.039781400 +0800 +@@ -330,7 +330,8 @@ + destroyPipe(channel->pipe); + } + +-static QString qt_create_commandline(const QString &program, const QStringList &arguments) ++static QString qt_create_commandline(const QString &program, const QStringList &arguments, ++ const QString &nativeArguments = QString()) + { + QString args; + if (!program.isEmpty()) { +@@ -359,6 +360,13 @@ + } + args += QLatin1Char(' ') + tmp; + } ++ ++ if (!nativeArguments.isEmpty()) { ++ if (!args.isEmpty()) ++ args += QLatin1Char(' '); ++ args += nativeArguments; ++ } ++ + return args; + } + +@@ -444,6 +452,30 @@ + return envlist; + } + ++bool QProcessPrivate::callCreateProcess(QProcess::CreateProcessArguments *cpargs) ++{ ++ if (modifyCreateProcessArgs) ++ modifyCreateProcessArgs(cpargs); ++ bool success = CreateProcess(cpargs->applicationName, cpargs->arguments, ++ cpargs->processAttributes, cpargs->threadAttributes, ++ cpargs->inheritHandles, cpargs->flags, cpargs->environment, ++ cpargs->currentDirectory, cpargs->startupInfo, ++ cpargs->processInformation); ++ if (stdinChannel.pipe[0] != INVALID_Q_PIPE) { ++ CloseHandle(stdinChannel.pipe[0]); ++ stdinChannel.pipe[0] = INVALID_Q_PIPE; ++ } ++ if (stdoutChannel.pipe[1] != INVALID_Q_PIPE) { ++ CloseHandle(stdoutChannel.pipe[1]); ++ stdoutChannel.pipe[1] = INVALID_Q_PIPE; ++ } ++ if (stderrChannel.pipe[1] != INVALID_Q_PIPE) { ++ CloseHandle(stderrChannel.pipe[1]); ++ stderrChannel.pipe[1] = INVALID_Q_PIPE; ++ } ++ return success; ++} ++ + void QProcessPrivate::startProcess() + { + Q_Q(QProcess); +@@ -498,11 +530,22 @@ + 0, 0, 0, + stdinChannel.pipe[0], stdoutChannel.pipe[1], stderrChannel.pipe[1] + }; +- success = CreateProcess(0, (wchar_t*)args.utf16(), +- 0, 0, TRUE, dwCreationFlags, +- environment.isEmpty() ? 0 : envlist.data(), +- workingDirectory.isEmpty() ? 0 : (wchar_t*)QDir::toNativeSeparators(workingDirectory).utf16(), +- &startupInfo, pid); ++ ++ const QString nativeWorkingDirectory = QDir::toNativeSeparators(workingDirectory); ++ QProcess::CreateProcessArguments cpargs = { ++ 0, (wchar_t*)args.utf16(), ++ 0, 0, TRUE, dwCreationFlags, ++ environment.isEmpty() ? 0 : envlist.data(), ++ nativeWorkingDirectory.isEmpty() ? Q_NULLPTR : (wchar_t*)nativeWorkingDirectory.utf16(), ++ &startupInfo, pid ++ }; ++ if (modifyCreateProcessArgs) ++ modifyCreateProcessArgs(&cpargs); ++ success = CreateProcess(cpargs.applicationName, cpargs.arguments, cpargs.processAttributes, ++ cpargs.threadAttributes, cpargs.inheritHandles, cpargs.flags, ++ cpargs.environment, cpargs.currentDirectory, cpargs.startupInfo, ++ cpargs.processInformation); ++ + QString errorString; + if (!success) { + // Capture the error string before we do CloseHandle below +@@ -818,6 +861,7 @@ + // Use ShellExecuteEx() to trigger an UAC prompt when CreateProcess()fails + // with ERROR_ELEVATION_REQUIRED. + static bool startDetachedUacPrompt(const QString &programIn, const QStringList &arguments, ++ const QString &nativeArguments, + const QString &workingDir, qint64 *pid) + { + typedef BOOL (WINAPI *ShellExecuteExType)(SHELLEXECUTEINFOW *); +@@ -828,11 +872,13 @@ + if (!shellExecuteEx) + return false; + +- const QString args = qt_create_commandline(QString(), arguments); // needs arguments only ++ const QString args = qt_create_commandline(QString(), // needs arguments only ++ arguments, nativeArguments); + SHELLEXECUTEINFOW shellExecuteExInfo; + memset(&shellExecuteExInfo, 0, sizeof(SHELLEXECUTEINFOW)); + shellExecuteExInfo.cbSize = sizeof(SHELLEXECUTEINFOW); +- shellExecuteExInfo.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_UNICODE | SEE_MASK_FLAG_NO_UI; ++ shellExecuteExInfo.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_UNICODE | SEE_MASK_FLAG_NO_UI | SEE_MASK_CLASSNAME; ++ shellExecuteExInfo.lpClass = L"exefile"; + shellExecuteExInfo.lpVerb = L"runas"; + const QString program = QDir::toNativeSeparators(programIn); + shellExecuteExInfo.lpFile = reinterpret_cast(program.utf16()); +@@ -850,6 +896,12 @@ + return true; + } + ++static bool startDetachedUacPrompt(const QString &programIn, const QStringList &arguments, ++ const QString &workingDir, qint64 *pid) ++{ ++ return startDetachedUacPrompt(programIn, arguments, QString(), workingDir, pid); ++} ++ + bool QProcessPrivate::startDetached(const QString &program, const QStringList &arguments, const QString &workingDir, qint64 *pid) + { + static const DWORD errorElevationRequired = 740; +@@ -880,6 +932,75 @@ + return success; + } + ++bool QProcessPrivate::startDetached(qint64 *pid) ++{ ++ static const DWORD errorElevationRequired = 740; ++ ++ if ((stdinChannel.type == Channel::Redirect && !openChannel(stdinChannel)) ++ || (stdoutChannel.type == Channel::Redirect && !openChannel(stdoutChannel)) ++ || (stderrChannel.type == Channel::Redirect && !openChannel(stderrChannel))) { ++ closeChannel(&stdinChannel); ++ closeChannel(&stdoutChannel); ++ closeChannel(&stderrChannel); ++ return false; ++ } ++ ++ QString args = qt_create_commandline(program, arguments, nativeArguments); ++ bool success = false; ++ PROCESS_INFORMATION pinfo; ++ ++ void *envPtr = nullptr; ++ QByteArray envlist; ++ if (environment.d.constData()) { ++ envlist = qt_create_environment(environment.d.constData()->hash); ++ envPtr = envlist.data(); ++ } ++ ++ DWORD dwCreationFlags = (GetConsoleWindow() ? 0 : CREATE_NO_WINDOW); ++ dwCreationFlags |= CREATE_UNICODE_ENVIRONMENT; ++ STARTUPINFOW startupInfo = { sizeof( STARTUPINFO ), 0, 0, 0, ++ (ulong)CW_USEDEFAULT, (ulong)CW_USEDEFAULT, ++ (ulong)CW_USEDEFAULT, (ulong)CW_USEDEFAULT, ++ 0, 0, 0, ++ STARTF_USESTDHANDLES, ++ 0, 0, 0, ++ stdinChannel.pipe[0], stdoutChannel.pipe[1], stderrChannel.pipe[1] ++ }; ++ ++ const bool inheritHandles = stdinChannel.type == Channel::Redirect ++ || stdoutChannel.type == Channel::Redirect ++ || stderrChannel.type == Channel::Redirect; ++ QProcess::CreateProcessArguments cpargs = { ++ nullptr, reinterpret_cast(const_cast(args.utf16())), ++ nullptr, nullptr, inheritHandles, dwCreationFlags, envPtr, ++ workingDirectory.isEmpty() ++ ? nullptr : reinterpret_cast(workingDirectory.utf16()), ++ &startupInfo, &pinfo ++ }; ++ success = callCreateProcess(&cpargs); ++ ++ if (success) { ++ CloseHandle(pinfo.hThread); ++ CloseHandle(pinfo.hProcess); ++ if (pid) ++ *pid = pinfo.dwProcessId; ++ } else if (GetLastError() == errorElevationRequired) { ++ if (envPtr) ++ qWarning("QProcess: custom environment will be ignored for detached elevated process."); ++ if (!stdinChannel.file.isEmpty() || !stdoutChannel.file.isEmpty() ++ || !stderrChannel.file.isEmpty()) { ++ qWarning("QProcess: file redirection is unsupported for detached elevated processes."); ++ } ++ success = startDetachedUacPrompt(program, arguments, nativeArguments, ++ workingDirectory, pid); ++ } ++ ++ closeChannel(&stdinChannel); ++ closeChannel(&stdoutChannel); ++ closeChannel(&stderrChannel); ++ return success; ++} ++ + QT_END_NAMESPACE + + #endif // QT_NO_PROCESS +diff --unified --recursive --text qtbase-opensource-src-5.6.3.orig/src/corelib/plugin/quuid.cpp qtbase-opensource-src-5.6.3/src/corelib/plugin/quuid.cpp +--- qtbase-opensource-src-5.6.3.orig/src/corelib/plugin/quuid.cpp 2017-09-06 20:13:54.000000000 +0800 ++++ qtbase-opensource-src-5.6.3/src/corelib/plugin/quuid.cpp 2023-10-17 14:38:05.822849000 +0800 +@@ -43,6 +43,8 @@ + #endif + QT_BEGIN_NAMESPACE + ++enum { MaxStringUuidLength = 38 }; ++ + template + void _q_toHex(Char *&dst, Integral value) + { +@@ -91,6 +93,30 @@ + *dst = Char('}'); + } + ++static char *_q_uuidToHex(const QUuid &uuid, char *dst, QUuid::StringFormat mode = QUuid::WithBraces) ++{ ++ if ((mode & QUuid::WithoutBraces) == 0) ++ *dst++ = '{'; ++ _q_toHex(dst, uuid.data1); ++ if ((mode & QUuid::Id128) != QUuid::Id128) ++ *dst++ = '-'; ++ _q_toHex(dst, uuid.data2); ++ if ((mode & QUuid::Id128) != QUuid::Id128) ++ *dst++ = '-'; ++ _q_toHex(dst, uuid.data3); ++ if ((mode & QUuid::Id128) != QUuid::Id128) ++ *dst++ = '-'; ++ for (int i = 0; i < 2; i++) ++ _q_toHex(dst, uuid.data4[i]); ++ if ((mode & QUuid::Id128) != QUuid::Id128) ++ *dst++ = '-'; ++ for (int i = 2; i < 8; i++) ++ _q_toHex(dst, uuid.data4[i]); ++ if ((mode & QUuid::WithoutBraces) == 0) ++ *dst++ = '}'; ++ return dst; ++} ++ + template + bool _q_uuidFromHex(const Char *&src, uint &d1, ushort &d2, ushort &d3, uchar (&d4)[8]) + { +@@ -550,6 +576,13 @@ + return result; + } + ++QString QUuid::toString(QUuid::StringFormat mode) const ++{ ++ char latin1[MaxStringUuidLength]; ++ const auto end = _q_uuidToHex(*this, latin1, mode); ++ return QString::fromLatin1(latin1, end - latin1); ++} ++ + /*! + Returns the binary representation of this QUuid. The byte array is + formatted as five hex fields separated by '-' and enclosed in +diff --unified --recursive --text qtbase-opensource-src-5.6.3.orig/src/corelib/plugin/quuid.h qtbase-opensource-src-5.6.3/src/corelib/plugin/quuid.h +--- qtbase-opensource-src-5.6.3.orig/src/corelib/plugin/quuid.h 2017-09-06 20:13:54.000000000 +0800 ++++ qtbase-opensource-src-5.6.3/src/corelib/plugin/quuid.h 2023-10-17 14:38:05.838486200 +0800 +@@ -74,6 +74,12 @@ + Sha1 = 5 // 0 1 0 1 + }; + ++ enum StringFormat { ++ WithBraces = 0, ++ WithoutBraces = 1, ++ Id128 = 3 ++ }; ++ + #if defined(Q_COMPILER_UNIFORM_INIT) && !defined(Q_QDOC) + Q_DECL_CONSTEXPR QUuid() Q_DECL_NOTHROW : data1(0), data2(0), data3(0), data4{0,0,0,0,0,0,0,0} {} + +@@ -108,6 +114,7 @@ + QUuid(const QString &); + QUuid(const char *); + QString toString() const; ++ QString toString(StringFormat mode) const; + QUuid(const QByteArray &); + QByteArray toByteArray() const; + QByteArray toRfc4122() const; +diff --unified --recursive --text qtbase-opensource-src-5.6.3.orig/src/corelib/tools/qchar.h qtbase-opensource-src-5.6.3/src/corelib/tools/qchar.h +--- qtbase-opensource-src-5.6.3.orig/src/corelib/tools/qchar.h 2017-09-06 20:13:54.000000000 +0800 ++++ qtbase-opensource-src-5.6.3/src/corelib/tools/qchar.h 2023-10-17 14:38:05.838486200 +0800 +@@ -572,6 +572,21 @@ + Q_DECL_CONSTEXPR inline bool operator> (QChar c1, QChar c2) { return operator< (c2, c1); } + Q_DECL_CONSTEXPR inline bool operator<=(QChar c1, QChar c2) { return !operator< (c2, c1); } + ++Q_DECL_CONSTEXPR inline bool operator==(QChar lhs, std::nullptr_t) Q_DECL_NOTHROW { return lhs.isNull(); } ++Q_DECL_CONSTEXPR inline bool operator< (QChar, std::nullptr_t) Q_DECL_NOTHROW { return false; } ++Q_DECL_CONSTEXPR inline bool operator==(std::nullptr_t, QChar rhs) Q_DECL_NOTHROW { return rhs.isNull(); } ++Q_DECL_CONSTEXPR inline bool operator< (std::nullptr_t, QChar rhs) Q_DECL_NOTHROW { return !rhs.isNull(); } ++ ++Q_DECL_CONSTEXPR inline bool operator!=(QChar lhs, std::nullptr_t) Q_DECL_NOTHROW { return !operator==(lhs, nullptr); } ++Q_DECL_CONSTEXPR inline bool operator>=(QChar lhs, std::nullptr_t) Q_DECL_NOTHROW { return !operator< (lhs, nullptr); } ++Q_DECL_CONSTEXPR inline bool operator> (QChar lhs, std::nullptr_t) Q_DECL_NOTHROW { return operator< (nullptr, lhs); } ++Q_DECL_CONSTEXPR inline bool operator<=(QChar lhs, std::nullptr_t) Q_DECL_NOTHROW { return !operator< (nullptr, lhs); } ++ ++Q_DECL_CONSTEXPR inline bool operator!=(std::nullptr_t, QChar rhs) Q_DECL_NOTHROW { return !operator==(nullptr, rhs); } ++Q_DECL_CONSTEXPR inline bool operator>=(std::nullptr_t, QChar rhs) Q_DECL_NOTHROW { return !operator< (nullptr, rhs); } ++Q_DECL_CONSTEXPR inline bool operator> (std::nullptr_t, QChar rhs) Q_DECL_NOTHROW { return operator< (rhs, nullptr); } ++Q_DECL_CONSTEXPR inline bool operator<=(std::nullptr_t, QChar rhs) Q_DECL_NOTHROW { return !operator< (rhs, nullptr); } ++ + #ifndef QT_NO_DATASTREAM + Q_CORE_EXPORT QDataStream &operator<<(QDataStream &, QChar); + Q_CORE_EXPORT QDataStream &operator>>(QDataStream &, QChar &); +diff --unified --recursive --text qtbase-opensource-src-5.6.3.orig/src/corelib/tools/qdatetime.cpp qtbase-opensource-src-5.6.3/src/corelib/tools/qdatetime.cpp +--- qtbase-opensource-src-5.6.3.orig/src/corelib/tools/qdatetime.cpp 2017-09-06 20:13:54.000000000 +0800 ++++ qtbase-opensource-src-5.6.3/src/corelib/tools/qdatetime.cpp 2023-10-17 14:38:05.838486200 +0800 +@@ -4135,6 +4135,17 @@ + - julianDayFromDate(1970, 1, 1)) * Q_INT64_C(86400000); + } + ++qint64 QDateTime::currentSecsSinceEpoch() Q_DECL_NOTHROW ++{ ++ SYSTEMTIME st; ++ memset(&st, 0, sizeof(SYSTEMTIME)); ++ GetSystemTime(&st); ++ ++ return st.wHour * SECS_PER_HOUR + st.wMinute * SECS_PER_MIN + st.wSecond + ++ qint64(julianDayFromDate(st.wYear, st.wMonth, st.wDay) ++ - julianDayFromDate(1970, 1, 1)) * Q_INT64_C(86400); ++} ++ + #elif defined(Q_OS_UNIX) + QDate QDate::currentDate() + { +diff --unified --recursive --text qtbase-opensource-src-5.6.3.orig/src/corelib/tools/qdatetime.h qtbase-opensource-src-5.6.3/src/corelib/tools/qdatetime.h +--- qtbase-opensource-src-5.6.3.orig/src/corelib/tools/qdatetime.h 2017-09-06 20:13:54.000000000 +0800 ++++ qtbase-opensource-src-5.6.3/src/corelib/tools/qdatetime.h 2023-10-17 14:38:05.838486200 +0800 +@@ -312,6 +312,7 @@ + static QDateTime fromMSecsSinceEpoch(qint64 msecs, const QTimeZone &timeZone); + #endif + static qint64 currentMSecsSinceEpoch() Q_DECL_NOTHROW; ++ static qint64 currentSecsSinceEpoch() Q_DECL_NOTHROW; + + #if defined(Q_OS_MAC) || defined(Q_QDOC) + static QDateTime fromCFDate(CFDateRef date); +diff --unified --recursive --text qtbase-opensource-src-5.6.3.orig/src/corelib/tools/qlocale.cpp qtbase-opensource-src-5.6.3/src/corelib/tools/qlocale.cpp +--- qtbase-opensource-src-5.6.3.orig/src/corelib/tools/qlocale.cpp 2017-09-06 20:13:54.000000000 +0800 ++++ qtbase-opensource-src-5.6.3/src/corelib/tools/qlocale.cpp 2023-10-17 14:38:05.854106100 +0800 +@@ -3526,6 +3526,48 @@ + return format.arg(str, sym); + } + ++QString QLocale::formattedDataSize(qint64 bytes, int precision, DataSizeFormats format) ++{ ++ int power, base = 1000; ++ if (!bytes) { ++ power = 0; ++ } else if (format & DataSizeBase1000) { ++ power = int(std::log10(qAbs(bytes)) / 3); ++ } else { // Compute log2(bytes) / 10: ++ power = int((63 - qCountLeadingZeroBits(quint64(qAbs(bytes)))) / 10); ++ base = 1024; ++ } ++ // Only go to doubles if we'll be using a quantifier: ++ const QString number = power ++ ? toString(bytes / std::pow(double(base), power), 'f', qMin(precision, 3 * power)) ++ : toString(bytes); ++ ++ // We don't support sizes in units larger than exbibytes because ++ // the number of bytes would not fit into qint64. ++ Q_ASSERT(power <= 6 && power >= 0); ++ // Red Panda C++: use hard-coded unit strings. ++ QString unit; ++ if (power > 0) { ++ if (format & DataSizeSIQuantifiers) { ++ static QString siQuantifiers[] { ++ QStringLiteral("kB"), QStringLiteral("MB"), QStringLiteral("GB"), ++ QStringLiteral("TB"), QStringLiteral("PB"), QStringLiteral("EB") ++ }; ++ unit = siQuantifiers[power - 1]; ++ } else { ++ static QString iecQuantifiers[] { ++ QStringLiteral("KiB"), QStringLiteral("MiB"), QStringLiteral("GiB"), ++ QStringLiteral("TiB"), QStringLiteral("PiB"), QStringLiteral("EiB") ++ }; ++ unit = iecQuantifiers[power - 1]; ++ } ++ } else { ++ unit = QStringLiteral("Bytes"); ++ } ++ ++ return number + QLatin1Char(' ') + unit; ++} ++ + /*! + \since 4.8 + +diff --unified --recursive --text qtbase-opensource-src-5.6.3.orig/src/corelib/tools/qlocale.h qtbase-opensource-src-5.6.3/src/corelib/tools/qlocale.h +--- qtbase-opensource-src-5.6.3.orig/src/corelib/tools/qlocale.h 2017-09-06 20:13:54.000000000 +0800 ++++ qtbase-opensource-src-5.6.3/src/corelib/tools/qlocale.h 2023-10-17 14:38:05.854106100 +0800 +@@ -854,6 +854,19 @@ + CurrencyDisplayName + }; + ++ enum DataSizeFormat { ++ // Single-bit values, for internal use. ++ DataSizeBase1000 = 1, // use factors of 1000 instead of IEC's 1024; ++ DataSizeSIQuantifiers = 2, // use SI quantifiers instead of IEC ones. ++ ++ // Flags values for use in API: ++ DataSizeIecFormat = 0, // base 1024, KiB, MiB, GiB, ... ++ DataSizeTraditionalFormat = DataSizeSIQuantifiers, // base 1024, kB, MB, GB, ... ++ DataSizeSIFormat = DataSizeBase1000 | DataSizeSIQuantifiers // base 1000, kB, MB, GB, ... ++ }; ++ Q_DECLARE_FLAGS(DataSizeFormats, DataSizeFormat) ++ Q_FLAG(DataSizeFormats) ++ + QLocale(); + QLocale(const QString &name); + QLocale(Language language, Country country = AnyCountry); +@@ -955,6 +968,8 @@ + QString toCurrencyString(double, const QString &symbol = QString()) const; + inline QString toCurrencyString(float, const QString &symbol = QString()) const; + ++ QString formattedDataSize(qint64 bytes, int precision = 2, DataSizeFormats format = DataSizeIecFormat); ++ + QStringList uiLanguages() const; + + bool operator==(const QLocale &other) const; +diff --unified --recursive --text qtbase-opensource-src-5.6.3.orig/src/corelib/tools/qstring.h qtbase-opensource-src-5.6.3/src/corelib/tools/qstring.h +--- qtbase-opensource-src-5.6.3.orig/src/corelib/tools/qstring.h 2017-09-06 20:13:54.000000000 +0800 ++++ qtbase-opensource-src-5.6.3/src/corelib/tools/qstring.h 2023-10-17 14:38:05.854106100 +0800 +@@ -258,6 +258,11 @@ + const QChar operator[](uint i) const; + QCharRef operator[](uint i); + ++ Q_REQUIRED_RESULT inline QChar front() const { return at(0); } ++ Q_REQUIRED_RESULT inline QCharRef front(); ++ Q_REQUIRED_RESULT inline QChar back() const { return at(size() - 1); } ++ Q_REQUIRED_RESULT inline QCharRef back(); ++ + QString arg(qlonglong a, int fieldwidth=0, int base=10, + QChar fillChar = QLatin1Char(' ')) const Q_REQUIRED_RESULT; + QString arg(qulonglong a, int fieldwidth=0, int base=10, +@@ -793,6 +798,10 @@ + + Data *d; + ++ friend inline bool operator==(QChar, const QString &) Q_DECL_NOTHROW; ++ friend inline bool operator< (QChar, const QString &) Q_DECL_NOTHROW; ++ friend inline bool operator> (QChar, const QString &) Q_DECL_NOTHROW; ++ + void reallocData(uint alloc, bool grow = false); + void expand(int i); + QString multiArg(int numArgs, const QString **args) const; +@@ -1094,6 +1103,8 @@ + { Q_ASSERT(i >= 0); return QCharRef(*this, i); } + inline QCharRef QString::operator[](uint i) + { return QCharRef(*this, i); } ++inline QCharRef QString::front() { return operator[](0); } ++inline QCharRef QString::back() { return operator[](size() - 1); } + inline QString::iterator QString::begin() + { detach(); return reinterpret_cast(d->data()); } + inline QString::const_iterator QString::begin() const +@@ -1573,6 +1584,25 @@ + inline int QStringRef::compare(const QStringRef &s1, QLatin1String s2, Qt::CaseSensitivity cs) + { return QString::compare_helper(s1.constData(), s1.length(), s2, cs); } + ++// QChar <> QString ++inline bool operator==(QChar lhs, const QString &rhs) Q_DECL_NOTHROW ++{ return rhs.size() == 1 && lhs == rhs.front(); } ++inline bool operator< (QChar lhs, const QString &rhs) Q_DECL_NOTHROW ++{ return QString::compare_helper(&lhs, 1, rhs.data(), rhs.size()) < 0; } ++inline bool operator> (QChar lhs, const QString &rhs) Q_DECL_NOTHROW ++{ return QString::compare_helper(&lhs, 1, rhs.data(), rhs.size()) > 0; } ++ ++inline bool operator!=(QChar lhs, const QString &rhs) Q_DECL_NOTHROW { return !(lhs == rhs); } ++inline bool operator<=(QChar lhs, const QString &rhs) Q_DECL_NOTHROW { return !(lhs > rhs); } ++inline bool operator>=(QChar lhs, const QString &rhs) Q_DECL_NOTHROW { return !(lhs < rhs); } ++ ++inline bool operator==(const QString &lhs, QChar rhs) Q_DECL_NOTHROW { return rhs == lhs; } ++inline bool operator!=(const QString &lhs, QChar rhs) Q_DECL_NOTHROW { return !(rhs == lhs); } ++inline bool operator< (const QString &lhs, QChar rhs) Q_DECL_NOTHROW { return rhs > lhs; } ++inline bool operator> (const QString &lhs, QChar rhs) Q_DECL_NOTHROW { return rhs < lhs; } ++inline bool operator<=(const QString &lhs, QChar rhs) Q_DECL_NOTHROW { return !(rhs < lhs); } ++inline bool operator>=(const QString &lhs, QChar rhs) Q_DECL_NOTHROW { return !(rhs > lhs); } ++ + inline int QString::localeAwareCompare(const QStringRef &s) const + { return localeAwareCompare_helper(constData(), length(), s.constData(), s.length()); } + inline int QString::localeAwareCompare(const QString& s1, const QStringRef& s2) +diff --unified --recursive --text qtbase-opensource-src-5.6.3.orig/src/gui/kernel/qcursor.cpp qtbase-opensource-src-5.6.3/src/gui/kernel/qcursor.cpp +--- qtbase-opensource-src-5.6.3.orig/src/gui/kernel/qcursor.cpp 2017-09-06 20:13:54.000000000 +0800 ++++ qtbase-opensource-src-5.6.3/src/gui/kernel/qcursor.cpp 2023-10-17 14:38:05.869731000 +0800 +@@ -471,6 +471,27 @@ + setShape(shape); + } + ++bool operator==(const QCursor &lhs, const QCursor &rhs) Q_DECL_NOTHROW ++{ ++ if (lhs.d == rhs.d) ++ return true; // Copy or same shape ++ ++ // Check pixmaps or bitmaps cache keys. Notice that having BitmapCursor ++ // shape implies either non-null pixmap or non-null bitmap and mask ++ if (lhs.shape() == Qt::BitmapCursor && rhs.shape() == Qt::BitmapCursor ++ && lhs.hotSpot() == rhs.hotSpot()) { ++ if (!lhs.d->pixmap.isNull()) ++ return lhs.d->pixmap.cacheKey() == rhs.d->pixmap.cacheKey(); ++ ++ if (!rhs.d->pixmap.isNull()) ++ return false; ++ ++ return lhs.d->bm->cacheKey() == rhs.d->bm->cacheKey() ++ && lhs.d->bmm->cacheKey() == rhs.d->bmm->cacheKey(); ++ } ++ ++ return false; ++} + + /*! + Returns the cursor shape identifier. The return value is one of +diff --unified --recursive --text qtbase-opensource-src-5.6.3.orig/src/gui/kernel/qcursor.h qtbase-opensource-src-5.6.3/src/gui/kernel/qcursor.h +--- qtbase-opensource-src-5.6.3.orig/src/gui/kernel/qcursor.h 2017-09-06 20:13:54.000000000 +0800 ++++ qtbase-opensource-src-5.6.3/src/gui/kernel/qcursor.h 2023-10-17 14:38:05.869731000 +0800 +@@ -102,9 +102,13 @@ + inline static void setPos(QScreen *screen, const QPoint &p) { setPos(screen, p.x(), p.y()); } + + private: ++ friend Q_GUI_EXPORT bool operator==(const QCursor &lhs, const QCursor &rhs) Q_DECL_NOTHROW; + QCursorData *d; + }; + ++Q_GUI_EXPORT bool operator==(const QCursor &lhs, const QCursor &rhs) Q_DECL_NOTHROW; ++inline bool operator!=(const QCursor &lhs, const QCursor &rhs) Q_DECL_NOTHROW { return !(lhs == rhs); } ++ + /***************************************************************************** + QCursor stream functions + *****************************************************************************/ +diff --unified --recursive --text qtbase-opensource-src-5.6.3.orig/src/gui/text/qfontmetrics.cpp qtbase-opensource-src-5.6.3/src/gui/text/qfontmetrics.cpp +--- qtbase-opensource-src-5.6.3.orig/src/gui/text/qfontmetrics.cpp 2017-09-06 20:13:54.000000000 +0800 ++++ qtbase-opensource-src-5.6.3/src/gui/text/qfontmetrics.cpp 2023-10-17 14:38:05.869731000 +0800 +@@ -586,6 +586,17 @@ + return qRound(advance); + } + ++// Rdd Panda C++: forward to `width`. ++int QFontMetrics::horizontalAdvance(const QString &text, int len) const ++{ ++ return width(text, len); ++} ++ ++int QFontMetrics::horizontalAdvance(QChar ch) const ++{ ++ return width(ch); ++} ++ + #if QT_VERSION < QT_VERSION_CHECK(6,0,0) + /*! \obsolete + +diff --unified --recursive --text qtbase-opensource-src-5.6.3.orig/src/gui/text/qfontmetrics.h qtbase-opensource-src-5.6.3/src/gui/text/qfontmetrics.h +--- qtbase-opensource-src-5.6.3.orig/src/gui/text/qfontmetrics.h 2017-09-06 20:13:54.000000000 +0800 ++++ qtbase-opensource-src-5.6.3/src/gui/text/qfontmetrics.h 2023-10-17 14:38:05.869731000 +0800 +@@ -86,6 +86,10 @@ + int width(const QString &, int len, int flags) const; + + int width(QChar) const; ++ ++ int horizontalAdvance(const QString &, int len = -1) const; ++ int horizontalAdvance(QChar) const; ++ + #if QT_VERSION < QT_VERSION_CHECK(6,0,0) + QT_DEPRECATED int charWidth(const QString &str, int pos) const; + #endif +diff --unified --recursive --text qtbase-opensource-src-5.6.3.orig/src/widgets/kernel/qaction.h qtbase-opensource-src-5.6.3/src/widgets/kernel/qaction.h +--- qtbase-opensource-src-5.6.3.orig/src/widgets/kernel/qaction.h 2017-09-06 20:13:54.000000000 +0800 ++++ qtbase-opensource-src-5.6.3/src/widgets/kernel/qaction.h 2023-10-18 08:45:39.996548800 +0800 +@@ -84,9 +84,9 @@ + NormalPriority = 128, + HighPriority = 256}; + Q_ENUM(Priority) +- explicit QAction(QObject* parent); +- QAction(const QString &text, QObject* parent); +- QAction(const QIcon &icon, const QString &text, QObject* parent); ++ explicit QAction(QObject* parent = nullptr); ++ QAction(const QString &text, QObject* parent = nullptr); ++ QAction(const QIcon &icon, const QString &text, QObject* parent = nullptr); + + ~QAction(); + +diff --unified --recursive --text qtbase-opensource-src-5.6.3.orig/src/widgets/kernel/qwidget.cpp qtbase-opensource-src-5.6.3/src/widgets/kernel/qwidget.cpp +--- qtbase-opensource-src-5.6.3.orig/src/widgets/kernel/qwidget.cpp 2017-09-06 20:13:54.000000000 +0800 ++++ qtbase-opensource-src-5.6.3/src/widgets/kernel/qwidget.cpp 2023-10-18 07:11:39.982967700 +0800 +@@ -10337,6 +10337,15 @@ + d->setWindowFlags(flags); + } + ++void QWidget::setWindowFlag(Qt::WindowType flag, bool on) ++{ ++ Q_D(QWidget); ++ if (on) ++ d->setWindowFlags(data->window_flags | flag); ++ else ++ d->setWindowFlags(data->window_flags & ~flag); ++} ++ + /*! \internal + + Implemented in QWidgetPrivate so that QMdiSubWindowPrivate can reimplement it. +diff --unified --recursive --text qtbase-opensource-src-5.6.3.orig/src/widgets/kernel/qwidget.h qtbase-opensource-src-5.6.3/src/widgets/kernel/qwidget.h +--- qtbase-opensource-src-5.6.3.orig/src/widgets/kernel/qwidget.h 2017-09-06 20:13:54.000000000 +0800 ++++ qtbase-opensource-src-5.6.3/src/widgets/kernel/qwidget.h 2023-10-18 07:10:13.033316200 +0800 +@@ -554,6 +554,7 @@ + + void setWindowFlags(Qt::WindowFlags type); + inline Qt::WindowFlags windowFlags() const; ++ void setWindowFlag(Qt::WindowType, bool on = true); + void overrideWindowFlags(Qt::WindowFlags type); + + inline Qt::WindowType windowType() const; diff --git a/tools/consolepauser/consolepauser.pro b/tools/consolepauser/consolepauser.pro index 3fcc6062..8aac7946 100644 --- a/tools/consolepauser/consolepauser.pro +++ b/tools/consolepauser/consolepauser.pro @@ -28,7 +28,8 @@ LIBS+= \ } win32: { -DEFINES += _WIN32_WINNT=0x0601 + DEFINES += _WIN32_WINNT=0x0501 + LIBS += -lpsapi # GetProcessMemoryInfo } CONFIG += lrelease