From f9cde2f283f05342fc190bfc4acc30a47cffdd3d Mon Sep 17 00:00:00 2001 From: John Preston Date: Mon, 30 Sep 2019 13:53:47 +0300 Subject: [PATCH] Initial commit. --- gyp.diff | 182 +++++ qtbase_5_6_2.diff | 1708 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 1890 insertions(+) create mode 100644 gyp.diff create mode 100644 qtbase_5_6_2.diff diff --git a/gyp.diff b/gyp.diff new file mode 100644 index 0000000..229cdb3 --- /dev/null +++ b/gyp.diff @@ -0,0 +1,182 @@ +diff --git a/pylib/gyp/MSVSVersion.py b/pylib/gyp/MSVSVersion.py +index 71582ccd..6c873b62 100644 +--- a/pylib/gyp/MSVSVersion.py ++++ b/pylib/gyp/MSVSVersion.py +@@ -268,7 +268,7 @@ def _CreateVersion(name, path, sdk_based=False): + uses_vcxproj=True, + path=path, + sdk_based=sdk_based, +- default_toolset='v141', ++ default_toolset='v142', + compatible_sdks=['v8.1', 'v10.0']), + '2017': VisualStudioVersion('2017', + 'Visual Studio 2017', +@@ -409,10 +409,18 @@ def _DetectVisualStudioVersions(versions_to_check, force_express): + '11.0': '2012', + '12.0': '2013', + '14.0': '2015', +- '15.0': '2017' ++ '15.0': '2017', ++ '16.0': '2019' + } ++ shell_path = os.environ.get('VSINSTALLDIR') ++ shell_path = _ConvertToCygpath(shell_path) if shell_path else None ++ shell_version = os.environ.get('VisualStudioVersion') if shell_path else None + versions = [] + for version in versions_to_check: ++ if version == shell_version: ++ if os.path.exists(shell_path): ++ versions.append(_CreateVersion(version_to_year[version], shell_path)) ++ + # Old method of searching for which VS version is installed + # We don't use the 2010-encouraged-way because we also want to get the + # path to the binaries, which it doesn't offer. +@@ -470,7 +478,7 @@ def SelectVisualStudioVersion(version='auto', allow_fallback=True): + if version == 'auto': + version = os.environ.get('GYP_MSVS_VERSION', 'auto') + version_map = { +- 'auto': ('15.0', '14.0', '12.0', '10.0', '9.0', '8.0', '11.0'), ++ 'auto': ('16.0', '15.0', '14.0', '12.0', '10.0', '9.0', '8.0', '11.0'), + '2005': ('8.0',), + '2005e': ('8.0',), + '2008': ('9.0',), +@@ -483,6 +491,7 @@ def SelectVisualStudioVersion(version='auto', allow_fallback=True): + '2013e': ('12.0',), + '2015': ('14.0',), + '2017': ('15.0',), ++ '2019': ('16.0',), + } + override_path = os.environ.get('GYP_MSVS_OVERRIDE_PATH') + if override_path: +diff --git a/pylib/gyp/generator/cmake.py b/pylib/gyp/generator/cmake.py +index 4a2041cf..e5333926 100644 +--- a/pylib/gyp/generator/cmake.py ++++ b/pylib/gyp/generator/cmake.py +@@ -1078,6 +1078,23 @@ def WriteTarget(namer, qualified_target, target_dicts, build_dir, config_to_use, + + output.write(')\n') + ++ # Precompile header ++ precompiled_header = config.get('cmake_precompiled_header', '') ++ if precompiled_header: ++ precompiled_header_script = config.get('cmake_precompiled_header_script', '') ++ if not precompiled_header_script: ++ print ('ERROR: cmake_precompiled_header requires cmake_precompiled_header_script') ++ cmake_precompiled_header = NormjoinPath(path_from_cmakelists_to_gyp, precompiled_header) ++ cmake_precompiled_header_script = NormjoinPathForceCMakeSource(path_from_cmakelists_to_gyp, precompiled_header_script) ++ output.write('include(') ++ output.write(cmake_precompiled_header_script) ++ output.write(')\n') ++ output.write('add_precompiled_header(') ++ output.write(cmake_target_name) ++ output.write(' ') ++ output.write(cmake_precompiled_header) ++ output.write(')\n') ++ + UnsetVariable(output, 'TOOLSET') + UnsetVariable(output, 'TARGET') + +@@ -1120,6 +1137,8 @@ def GenerateOutputForConfig(target_list, target_dicts, data, + SetVariable(output, 'configuration', config_to_use) + + ar = None ++ ranlib = None ++ nm = None + cc = None + cxx = None + +@@ -1129,17 +1148,27 @@ def GenerateOutputForConfig(target_list, target_dicts, data, + for key, value in make_global_settings: + if key == 'AR': + ar = os.path.join(build_to_top, value) ++ if key == 'RANLIB': ++ ranlib = os.path.join(build_to_top, value) ++ if key == 'NM': ++ nm = os.path.join(build_to_top, value) + if key == 'CC': + cc = os.path.join(build_to_top, value) + if key == 'CXX': + cxx = os.path.join(build_to_top, value) + + ar = gyp.common.GetEnvironFallback(['AR_target', 'AR'], ar) ++ ranlib = gyp.common.GetEnvironFallback(['RANLIB_target', 'RANLIB'], ranlib) ++ nm = gyp.common.GetEnvironFallback(['NM_target', 'NM'], nm) + cc = gyp.common.GetEnvironFallback(['CC_target', 'CC'], cc) + cxx = gyp.common.GetEnvironFallback(['CXX_target', 'CXX'], cxx) + + if ar: + SetVariable(output, 'CMAKE_AR', ar) ++ if ranlib: ++ SetVariable(output, 'CMAKE_RANLIB', ranlib) ++ if nm: ++ SetVariable(output, 'CMAKE_NM', nm) + if cc: + SetVariable(output, 'CMAKE_C_COMPILER', cc) + if cxx: +diff --git a/pylib/gyp/generator/xcode.py b/pylib/gyp/generator/xcode.py +index 8bc22bed..24bee427 100644 +--- a/pylib/gyp/generator/xcode.py ++++ b/pylib/gyp/generator/xcode.py +@@ -74,6 +74,12 @@ generator_additional_non_configuration_keys = [ + 'ios_app_extension', + 'ios_watch_app', + 'ios_watchkit_extension', ++ ++ 'mac_sandbox', # sandbox support ++ 'mac_sandbox_development_team', ++ ++ 'mac_hardened_runtime', # hardened runtime support ++ + 'mac_bundle', + 'mac_bundle_resources', + 'mac_framework_headers', +@@ -774,6 +780,39 @@ def GenerateOutput(target_list, target_dicts, data, params): + xcode_targets[qualified_target] = xct + xcode_target_to_target_dict[xct] = spec + ++ # sandbox and hardened runtime support ++ is_sandbox = int(spec.get('mac_sandbox', 0)) ++ is_hardened_runtime = int(spec.get('mac_hardened_runtime', 0)) ++ if is_sandbox or is_hardened_runtime: ++ try: ++ tmp = pbxp._properties['attributes']['TargetAttributes'] ++ except KeyError: ++ pbxp._properties['attributes']['TargetAttributes'] = {} ++ try: ++ tmp = pbxp._properties['attributes']['TargetAttributes'][xct] ++ except KeyError: ++ pbxp._properties['attributes']['TargetAttributes'][xct] = {} ++ try: ++ tmp = pbxp._properties['attributes']['TargetAttributes'][xct]['SystemCapabilities'] ++ except KeyError: ++ pbxp._properties['attributes']['TargetAttributes'][xct]['SystemCapabilities'] = {} ++ ++ if is_sandbox: ++ dev_team = spec.get('mac_sandbox_development_team', '%%ERROR%%') ++ assert dev_team != '%%ERROR%%', ( ++ 'mac_sandbox must be accompanied by mac_sandbox_development_team (target "%s")' % ++ target_name) ++ pbxp._properties['attributes']['TargetAttributes'][xct]['DevelopmentTeam'] = dev_team ++ pbxp._properties['attributes']['TargetAttributes'][xct]['SystemCapabilities']['com.apple.Sandbox'] = { ++ 'enabled': 1, ++ } ++ ++ # hardened runtime support ++ if is_hardened_runtime: ++ pbxp._properties['attributes']['TargetAttributes'][xct]['SystemCapabilities']['com.apple.HardenedRuntime'] = { ++ 'enabled': 1, ++ } ++ + spec_actions = spec.get('actions', []) + spec_rules = spec.get('rules', []) + +@@ -1132,7 +1171,8 @@ exit 1 + groups = [x for x in groups if not x.endswith('_excluded')] + for group in groups: + for item in rule.get(group, []): +- pbxp.AddOrGetFileInRootGroup(item) ++ concrete_item = ExpandXcodeVariables(item, rule_input_dict) ++ pbxp.AddOrGetFileInRootGroup(concrete_item) + + # Add "sources". + for source in spec.get('sources', []): diff --git a/qtbase_5_6_2.diff b/qtbase_5_6_2.diff new file mode 100644 index 0000000..92a5451 --- /dev/null +++ b/qtbase_5_6_2.diff @@ -0,0 +1,1708 @@ +diff --git a/mkspecs/common/msvc-desktop.conf b/mkspecs/common/msvc-desktop.conf +index eec9e1f688..7ae53c7a1e 100644 +--- a/mkspecs/common/msvc-desktop.conf ++++ b/mkspecs/common/msvc-desktop.conf +@@ -30,9 +30,10 @@ QMAKE_YACCFLAGS = -d + QMAKE_CFLAGS = -nologo -Zc:wchar_t + QMAKE_CFLAGS_WARN_ON = -W3 + QMAKE_CFLAGS_WARN_OFF = -W0 +-QMAKE_CFLAGS_RELEASE = -O2 -MD +-QMAKE_CFLAGS_RELEASE_WITH_DEBUGINFO += -O2 -MD -Zi +-QMAKE_CFLAGS_DEBUG = -Zi -MDd ++# Patch: Make this build use static runtime library. ++QMAKE_CFLAGS_RELEASE = -O2 -MT ++QMAKE_CFLAGS_RELEASE_WITH_DEBUGINFO += -O2 -MT -Zi ++QMAKE_CFLAGS_DEBUG = -Zi -MTd + QMAKE_CFLAGS_YACC = + QMAKE_CFLAGS_LTCG = -GL + QMAKE_CFLAGS_SSE2 = -arch:SSE2 +diff --git a/src/corelib/io/qfsfileengine_win.cpp b/src/corelib/io/qfsfileengine_win.cpp +index 391fbcc519..d07802bb7a 100644 +--- a/src/corelib/io/qfsfileengine_win.cpp ++++ b/src/corelib/io/qfsfileengine_win.cpp +@@ -427,11 +427,12 @@ qint64 QFSFileEnginePrivate::nativeWrite(const char *data, qint64 len) + + // Writing on Windows fails with ERROR_NO_SYSTEM_RESOURCES when + // the chunks are too large, so we limit the block size to 32MB. +- const DWORD blockSize = DWORD(qMin(bytesToWrite, qint64(32 * 1024 * 1024))); + qint64 totalWritten = 0; + do { ++ // Patch: backport critical bugfix from '683c9bc4a8' commit. ++ const DWORD currentBlockSize = DWORD(qMin(bytesToWrite, qint64(32 * 1024 * 1024))); + DWORD bytesWritten; +- if (!WriteFile(fileHandle, data + totalWritten, blockSize, &bytesWritten, NULL)) { ++ if (!WriteFile(fileHandle, data + totalWritten, currentBlockSize, &bytesWritten, NULL)) { + if (totalWritten == 0) { + // Note: Only return error if the first WriteFile failed. + q->setError(QFile::WriteError, qt_error_string()); +diff --git a/src/corelib/tools/qunicodetables.cpp b/src/corelib/tools/qunicodetables.cpp +index 14e4fd10aa..0619a176a7 100644 +--- a/src/corelib/tools/qunicodetables.cpp ++++ b/src/corelib/tools/qunicodetables.cpp +@@ -6227,7 +6227,8 @@ static const Properties uc_properties[] = { + { 1, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 0, 7, 4, 4, 21, 11 }, + { 0, 17, 230, 5, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 4, 4, 4, 21, 11 }, + { 18, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 85, 0, 8, 8, 12, 11 }, +- { 25, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 12, 17, 2 }, ++ // Patch: Some bad characters appeared in ui in case 2 was here instead of 11. ++ { 25, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 12, 17, 11 }, + { 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 14, 9, 11, 11 }, + { 3, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 14, 9, 11, 11 }, + { 3, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 14, 9, 11, 11 }, +diff --git a/src/gui/kernel/qhighdpiscaling.cpp b/src/gui/kernel/qhighdpiscaling.cpp +index 2d00b9dce9..eeba86e936 100644 +--- a/src/gui/kernel/qhighdpiscaling.cpp ++++ b/src/gui/kernel/qhighdpiscaling.cpp +@@ -51,6 +51,9 @@ static const char screenFactorsEnvVar[] = "QT_SCREEN_SCALE_FACTORS"; + + static inline qreal initialGlobalScaleFactor() + { ++ // Patch: Disable environment variable dpi scaling changing. ++ // It is not supported by Telegram Desktop :( ++ return 1.; + + qreal result = 1; + if (qEnvironmentVariableIsSet(scaleFactorEnvVar)) { +diff --git a/src/gui/kernel/qplatformdialoghelper.h b/src/gui/kernel/qplatformdialoghelper.h +index 5b2f4ece77..790db46d25 100644 +--- a/src/gui/kernel/qplatformdialoghelper.h ++++ b/src/gui/kernel/qplatformdialoghelper.h +@@ -386,6 +386,10 @@ public: + virtual QUrl directory() const = 0; + virtual void selectFile(const QUrl &filename) = 0; + virtual QList selectedFiles() const = 0; ++ ++ // Patch: Adding select-by-url for Windows file dialog. ++ virtual QByteArray selectedRemoteContent() const { return QByteArray(); } ++ + virtual void setFilter() = 0; + virtual void selectNameFilter(const QString &filter) = 0; + virtual QString selectedNameFilter() const = 0; +diff --git a/src/gui/kernel/qwindow.cpp b/src/gui/kernel/qwindow.cpp +index bcd29b6fe1..bcb0672f69 100644 +--- a/src/gui/kernel/qwindow.cpp ++++ b/src/gui/kernel/qwindow.cpp +@@ -2525,7 +2525,8 @@ void QWindowPrivate::setCursor(const QCursor *newCursor) + void QWindowPrivate::applyCursor() + { + Q_Q(QWindow); +- if (platformWindow) { ++ // Patch: Fixing possible crash (crashdumps point on this code line). ++ if (platformWindow && q->screen() && q->screen()->handle()) { + if (QPlatformCursor *platformCursor = q->screen()->handle()->cursor()) { + QCursor *c = QGuiApplication::overrideCursor(); + if (!c && hasCursor) +diff --git a/src/gui/painting/qbezier.cpp b/src/gui/painting/qbezier.cpp +index 8e0e76f787..a61bd62834 100644 +--- a/src/gui/painting/qbezier.cpp ++++ b/src/gui/painting/qbezier.cpp +@@ -45,6 +45,34 @@ QT_BEGIN_NAMESPACE + + //#define QDEBUG_BEZIER + ++// Patch: Workaround VS2019 compiler bug, see QTBUG-75280. ++#ifdef Q_OS_WIN ++Q_NEVER_INLINE void QBezier::split(QBezier *firstHalf, QBezier *secondHalf) const ++{ ++ Q_ASSERT(firstHalf); ++ Q_ASSERT(secondHalf); ++ ++ qreal c = (x2 + x3)*.5; ++ firstHalf->x2 = (x1 + x2)*.5; ++ secondHalf->x3 = (x3 + x4)*.5; ++ firstHalf->x1 = x1; ++ secondHalf->x4 = x4; ++ firstHalf->x3 = (firstHalf->x2 + c)*.5; ++ secondHalf->x2 = (secondHalf->x3 + c)*.5; ++ firstHalf->x4 = secondHalf->x1 = (firstHalf->x3 + secondHalf->x2)*.5; ++ ++ c = (y2 + y3)/2; ++ firstHalf->y2 = (y1 + y2)*.5; ++ secondHalf->y3 = (y3 + y4)*.5; ++ firstHalf->y1 = y1; ++ secondHalf->y4 = y4; ++ firstHalf->y3 = (firstHalf->y2 + c)*.5; ++ secondHalf->y2 = (secondHalf->y3 + c)*.5; ++ firstHalf->y4 = secondHalf->y1 = (firstHalf->y3 + secondHalf->y2)*.5; ++} ++// Patch: Workaround VS2019 compiler bug, see QTBUG-75280. ++#endif // Q_OS_WIN ++ + /*! + \internal + */ +diff --git a/src/gui/painting/qbezier_p.h b/src/gui/painting/qbezier_p.h +index dd1cd94acf..aedc8b6a4b 100644 +--- a/src/gui/painting/qbezier_p.h ++++ b/src/gui/painting/qbezier_p.h +@@ -215,6 +215,8 @@ inline QPointF QBezier::secondDerivedAt(qreal t) const + a * y1 + b * y2 + c * y3 + d * y4); + } + ++// Patch: Workaround VS2019 compiler bug, see QTBUG-75280. ++#ifndef Q_OS_WIN + inline void QBezier::split(QBezier *firstHalf, QBezier *secondHalf) const + { + Q_ASSERT(firstHalf); +@@ -238,6 +240,8 @@ inline void QBezier::split(QBezier *firstHalf, QBezier *secondHalf) const + secondHalf->y2 = (secondHalf->y3 + c)*.5; + firstHalf->y4 = secondHalf->y1 = (firstHalf->y3 + secondHalf->y2)*.5; + } ++// Patch: Workaround VS2019 compiler bug, see QTBUG-75280. ++#endif // Q_OS_WIN + + inline void QBezier::parameterSplitLeft(qreal t, QBezier *left) + { +diff --git a/src/gui/painting/qpaintengine_p.h b/src/gui/painting/qpaintengine_p.h +index 918c98997b..4158259743 100644 +--- a/src/gui/painting/qpaintengine_p.h ++++ b/src/gui/painting/qpaintengine_p.h +@@ -80,8 +80,18 @@ public: + if (hasSystemTransform) { + if (systemTransform.type() <= QTransform::TxTranslate) + systemClip.translate(qRound(systemTransform.dx()), qRound(systemTransform.dy())); +- else ++ // Patch: Transform the system clip region back from device pixels to device-independent pixels before ++ // applying systemTransform, which already has transform from device-independent pixels to device pixels. ++ else { ++#ifdef Q_OS_MAC ++ QTransform scaleTransform; ++ const qreal invDevicePixelRatio = 1. / pdev->devicePixelRatio(); ++ scaleTransform.scale(invDevicePixelRatio, invDevicePixelRatio); ++ systemClip = systemTransform.map(scaleTransform.map(systemClip)); ++#else + systemClip = systemTransform.map(systemClip); ++#endif ++ } + } + + // Make sure we're inside the viewport. +diff --git a/src/gui/text/qtextengine_p.h b/src/gui/text/qtextengine_p.h +index 7e507bba2d..936e7a92cb 100644 +--- a/src/gui/text/qtextengine_p.h ++++ b/src/gui/text/qtextengine_p.h +@@ -283,7 +283,8 @@ private: + + struct QScriptItem; + /// Internal QTextItem +-class QTextItemInt : public QTextItem ++// Patch: Enable access to QTextItemInt in .dll for WinRT build. ++class Q_GUI_EXPORT QTextItemInt : public QTextItem + { + public: + inline QTextItemInt() +diff --git a/src/gui/text/qtextlayout.cpp b/src/gui/text/qtextlayout.cpp +index aca475a581..5fa0be2c45 100644 +--- a/src/gui/text/qtextlayout.cpp ++++ b/src/gui/text/qtextlayout.cpp +@@ -694,6 +694,9 @@ int QTextLayout::nextCursorPosition(int oldPos, CursorMode mode) const + while (oldPos < len && !attributes[oldPos].graphemeBoundary) + oldPos++; + } else { ++ // Patch: Skip to the end of the current word, not to the start of the next one. ++ while (oldPos < len && attributes[oldPos].whiteSpace) ++ oldPos++; + if (oldPos < len && d->atWordSeparator(oldPos)) { + oldPos++; + while (oldPos < len && d->atWordSeparator(oldPos)) +@@ -702,8 +705,9 @@ int QTextLayout::nextCursorPosition(int oldPos, CursorMode mode) const + while (oldPos < len && !attributes[oldPos].whiteSpace && !d->atWordSeparator(oldPos)) + oldPos++; + } +- while (oldPos < len && attributes[oldPos].whiteSpace) +- oldPos++; ++ // Patch: Skip to the end of the current word, not to the start of the next one. ++ //while (oldPos < len && attributes[oldPos].whiteSpace) ++ // oldPos++; + } + + return oldPos; +@@ -1645,6 +1649,9 @@ namespace { + int currentPosition; + glyph_t previousGlyph; + ++ // Patch: Fix a crash in right bearing calculation. ++ QFontEngine *previousGlyphFontEngine; ++ + QFixed minw; + QFixed softHyphenWidth; + QFixed rightBearing; +@@ -1677,13 +1684,19 @@ namespace { + if (currentPosition > 0 && + logClusters[currentPosition - 1] < glyphs.numGlyphs) { + previousGlyph = currentGlyph(); // needed to calculate right bearing later ++ ++ // Patch: Fix a crash in right bearing calculation. ++ previousGlyphFontEngine = fontEngine; + } + } + +- inline void calculateRightBearing(glyph_t glyph) ++ // Patch: Fix a crash in right bearing calculation. ++ inline void calculateRightBearing(QFontEngine *engine, glyph_t glyph) + { + qreal rb; +- fontEngine->getGlyphBearings(glyph, 0, &rb); ++ ++ // Patch: Fix a crash in right bearing calculation. ++ engine->getGlyphBearings(glyph, 0, &rb); + + // We only care about negative right bearings, so we limit the range + // of the bearing here so that we can assume it's negative in the rest +@@ -1696,13 +1709,16 @@ namespace { + { + if (currentPosition <= 0) + return; +- calculateRightBearing(currentGlyph()); ++ ++ // Patch: Fix a crash in right bearing calculation. ++ calculateRightBearing(fontEngine, currentGlyph()); + } + + inline void calculateRightBearingForPreviousGlyph() + { + if (previousGlyph > 0) +- calculateRightBearing(previousGlyph); ++ // Patch: Fix a crash in right bearing calculation. ++ calculateRightBearing(previousGlyphFontEngine, previousGlyph); + } + + static const QFixed RightBearingNotCalculated; +diff --git a/src/gui/text/qtextlayout.h b/src/gui/text/qtextlayout.h +index f74d4d4229..8ad672c9fe 100644 +--- a/src/gui/text/qtextlayout.h ++++ b/src/gui/text/qtextlayout.h +@@ -196,6 +196,9 @@ private: + QRectF *brect, int tabstops, int* tabarray, int tabarraylen, + QPainter *painter); + QTextEngine *d; ++ ++ // Patch: Allow access to private constructor. ++ friend class TextBlock; + }; + + +diff --git a/src/network/access/qhttpnetworkconnection.cpp b/src/network/access/qhttpnetworkconnection.cpp +index c4cb8e65c0..45793e364f 100644 +--- a/src/network/access/qhttpnetworkconnection.cpp ++++ b/src/network/access/qhttpnetworkconnection.cpp +@@ -110,6 +110,8 @@ QHttpNetworkConnectionPrivate::~QHttpNetworkConnectionPrivate() + { + for (int i = 0; i < channelCount; ++i) { + if (channels[i].socket) { ++ // Patch: backport critical bugfix from '4f959b6b30' commit. ++ QObject::disconnect(channels[i].socket, Q_NULLPTR, &channels[i], Q_NULLPTR); + channels[i].socket->close(); + delete channels[i].socket; + } +diff --git a/src/network/access/qnetworkreplyhttpimpl.cpp b/src/network/access/qnetworkreplyhttpimpl.cpp +index 94235a48dd..9abd2cc0a1 100644 +--- a/src/network/access/qnetworkreplyhttpimpl.cpp ++++ b/src/network/access/qnetworkreplyhttpimpl.cpp +@@ -2045,6 +2045,9 @@ void QNetworkReplyHttpImplPrivate::finished() + { + Q_Q(QNetworkReplyHttpImpl); + ++ // Patch: Fix crash in Linux (by crashreports). ++ QPointer guard = q; ++ + if (state == Finished || state == Aborted || state == WaitingForSession) + return; + +@@ -2075,6 +2078,9 @@ void QNetworkReplyHttpImplPrivate::finished() + #endif + } + ++ // Patch: Fix crash in Linux (by crashreports). ++ if (!guard) return; ++ + // if we don't know the total size of or we received everything save the cache + if (totalSize.isNull() || totalSize == -1 || bytesDownloaded == totalSize) + completeCacheSave(); +@@ -2084,6 +2090,9 @@ void QNetworkReplyHttpImplPrivate::finished() + if (isHttpRedirectResponse() && errorCode == QNetworkReply::NoError) + return; + ++ // Patch: Fix crash in Linux (by crashreports). ++ if (!guard) return; ++ + state = Finished; + q->setFinished(true); + +diff --git a/src/network/socket/qnativesocketengine_win.cpp b/src/network/socket/qnativesocketengine_win.cpp +index 41834b21ae..8cdf4ab145 100644 +--- a/src/network/socket/qnativesocketengine_win.cpp ++++ b/src/network/socket/qnativesocketengine_win.cpp +@@ -675,6 +675,13 @@ bool QNativeSocketEnginePrivate::nativeConnect(const QHostAddress &address, quin + errorDetected = true; + break; + } ++ // Patch: Handle network unreachable the same as host unreachable. ++ if (value == WSAENETUNREACH) { ++ setError(QAbstractSocket::NetworkError, NetworkUnreachableErrorString); ++ socketState = QAbstractSocket::UnconnectedState; ++ errorDetected = true; ++ break; ++ } + if (value == WSAEADDRNOTAVAIL) { + setError(QAbstractSocket::NetworkError, AddressNotAvailableErrorString); + socketState = QAbstractSocket::UnconnectedState; +diff --git a/src/platformsupport/cglconvenience/cglconvenience.mm b/src/platformsupport/cglconvenience/cglconvenience.mm +index fb609ae485..ef1c638d91 100644 +--- a/src/platformsupport/cglconvenience/cglconvenience.mm ++++ b/src/platformsupport/cglconvenience/cglconvenience.mm +@@ -128,7 +128,12 @@ void *qcgl_createNSOpenGLPixelFormat(const QSurfaceFormat &format) + if (format.stereo()) + attrs << NSOpenGLPFAStereo; + +- attrs << NSOpenGLPFAAllowOfflineRenderers; ++ // Patch: Fix macOS regression. On 10.14.4, it crashes on GPU switches. ++ // See https://bugreports.qt.io/browse/QTCREATORBUG-22215 ++ static const QAppleOperatingSystemVersion version = qt_apple_os_version(); ++ if (!(version.major == 10 && version.minor == 14 && version.patch == 4)) { ++ attrs << NSOpenGLPFAAllowOfflineRenderers; ++ } + + QByteArray useLayer = qgetenv("QT_MAC_WANTS_LAYER"); + if (!useLayer.isEmpty() && useLayer.toInt() > 0) { +diff --git a/src/platformsupport/dbustray/qdbustrayicon.cpp b/src/platformsupport/dbustray/qdbustrayicon.cpp +index 4d6e70720d..9bdb0beb67 100644 +--- a/src/platformsupport/dbustray/qdbustrayicon.cpp ++++ b/src/platformsupport/dbustray/qdbustrayicon.cpp +@@ -58,9 +58,18 @@ QT_BEGIN_NAMESPACE + + Q_LOGGING_CATEGORY(qLcTray, "qt.qpa.tray") + ++static QString cachePath() ++{ ++ QString xdgCache = QString::fromUtf8(getenv("XDG_CACHE_HOME")); ++ if (xdgCache.isEmpty()) { ++ xdgCache = QDir::cleanPath(QDir::homePath() + QStringLiteral("/.cache")); ++ } ++ return xdgCache; ++} ++ + static const QString KDEItemFormat = QStringLiteral("org.kde.StatusNotifierItem-%1-%2"); + static const QString KDEWatcherService = QStringLiteral("org.kde.StatusNotifierWatcher"); +-static const QString TempFileTemplate = QDir::tempPath() + QStringLiteral("/qt-trayicon-XXXXXX.png"); ++static const QString TempFileTemplate = cachePath() + QStringLiteral("/qt-trayicon-XXXXXX.png"); + static const QString XdgNotificationService = QStringLiteral("org.freedesktop.Notifications"); + static const QString XdgNotificationPath = QStringLiteral("/org/freedesktop/Notifications"); + static const QString DefaultAction = QStringLiteral("default"); +@@ -151,6 +160,12 @@ QTemporaryFile *QDBusTrayIcon::tempIcon(const QIcon &icon) + uint pid = session.interface()->servicePid(KDEWatcherService).value(); + QString processName = QLockFilePrivate::processNameByPid(pid); + necessary = processName.endsWith(QStringLiteral("indicator-application-service")); ++ if (!necessary) { ++ QString xdgDesktop = QString::fromUtf8(getenv("XDG_CURRENT_DESKTOP")); ++ QStringList desktops = xdgDesktop.toLower().split(QLatin1Char(':')); ++ necessary = desktops.contains(QStringLiteral("unity")) || ++ desktops.contains(QStringLiteral("ubuntu")); ++ } + necessity_checked = true; + } + if (!necessary) +diff --git a/src/platformsupport/fontdatabases/basic/qbasicfontdatabase.cpp b/src/platformsupport/fontdatabases/basic/qbasicfontdatabase.cpp +index 728b166b71..1dc64593e1 100644 +--- a/src/platformsupport/fontdatabases/basic/qbasicfontdatabase.cpp ++++ b/src/platformsupport/fontdatabases/basic/qbasicfontdatabase.cpp +@@ -172,6 +172,79 @@ void QBasicFontDatabase::releaseHandle(void *handle) + + extern FT_Library qt_getFreetype(); + ++// Patch: Enable Open Sans Semibold font family reading. ++// Copied from freetype with some modifications. ++ ++#ifndef FT_PARAM_TAG_IGNORE_PREFERRED_FAMILY ++#define FT_PARAM_TAG_IGNORE_PREFERRED_FAMILY FT_MAKE_TAG('i', 'g', 'p', 'f') ++#endif ++ ++#ifndef FT_PARAM_TAG_IGNORE_PREFERRED_SUBFAMILY ++#define FT_PARAM_TAG_IGNORE_PREFERRED_SUBFAMILY FT_MAKE_TAG('i', 'g', 'p', 's') ++#endif ++ ++/* there's a Mac-specific extended implementation of FT_New_Face() */ ++/* in src/base/ftmac.c */ ++ ++#if !defined( FT_MACINTOSH ) || defined( DARWIN_NO_CARBON ) ++ ++/* documentation is in freetype.h */ ++ ++FT_Error __ft_New_Face(FT_Library library, const char* pathname, FT_Long face_index, FT_Face *aface) { ++ FT_Open_Args args; ++ ++ /* test for valid `library' and `aface' delayed to FT_Open_Face() */ ++ if (!pathname) ++ return FT_Err_Invalid_Argument; ++ ++ FT_Parameter params[2]; ++ params[0].tag = FT_PARAM_TAG_IGNORE_PREFERRED_FAMILY; ++ params[0].data = 0; ++ params[1].tag = FT_PARAM_TAG_IGNORE_PREFERRED_SUBFAMILY; ++ params[1].data = 0; ++ args.flags = FT_OPEN_PATHNAME | FT_OPEN_PARAMS; ++ args.pathname = (char*)pathname; ++ args.stream = NULL; ++ args.num_params = 2; ++ args.params = params; ++ ++ return FT_Open_Face(library, &args, face_index, aface); ++} ++ ++#else ++ ++FT_Error __ft_New_Face(FT_Library library, const char* pathname, FT_Long face_index, FT_Face *aface) { ++ return FT_New_Face(library, pathname, face_index, aface); ++} ++ ++#endif /* defined( FT_MACINTOSH ) && !defined( DARWIN_NO_CARBON ) */ ++ ++/* documentation is in freetype.h */ ++ ++FT_Error __ft_New_Memory_Face(FT_Library library, const FT_Byte* file_base, FT_Long file_size, FT_Long face_index, FT_Face *aface) { ++ FT_Open_Args args; ++ ++ /* test for valid `library' and `face' delayed to FT_Open_Face() */ ++ if (!file_base) ++ return FT_Err_Invalid_Argument; ++ ++ FT_Parameter params[2]; ++ params[0].tag = FT_PARAM_TAG_IGNORE_PREFERRED_FAMILY; ++ params[0].data = 0; ++ params[1].tag = FT_PARAM_TAG_IGNORE_PREFERRED_SUBFAMILY; ++ params[1].data = 0; ++ args.flags = FT_OPEN_MEMORY | FT_OPEN_PARAMS; ++ args.memory_base = file_base; ++ args.memory_size = file_size; ++ args.stream = NULL; ++ args.num_params = 2; ++ args.params = params; ++ ++ return FT_Open_Face(library, &args, face_index, aface); ++} ++ ++// end ++ + QStringList QBasicFontDatabase::addTTFile(const QByteArray &fontData, const QByteArray &file) + { + FT_Library library = qt_getFreetype(); +@@ -183,9 +256,11 @@ QStringList QBasicFontDatabase::addTTFile(const QByteArray &fontData, const QByt + FT_Face face; + FT_Error error; + if (!fontData.isEmpty()) { +- error = FT_New_Memory_Face(library, (const FT_Byte *)fontData.constData(), fontData.size(), index, &face); ++ // Patch: Enable Open Sans Semibold font family reading. ++ error = __ft_New_Memory_Face(library, (const FT_Byte *)fontData.constData(), fontData.size(), index, &face); + } else { +- error = FT_New_Face(library, file.constData(), index, &face); ++ // Patch: Enable Open Sans Semibold font family reading. ++ error = __ft_New_Face(library, file.constData(), index, &face); + } + if (error != FT_Err_Ok) { + qDebug() << "FT_New_Face failed with index" << index << ':' << hex << error; +diff --git a/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp b/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp +index 8ebabf3419..7bb8abd0d0 100644 +--- a/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp ++++ b/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp +@@ -375,6 +375,17 @@ static void populateFromPattern(FcPattern *pattern) + + familyName = QString::fromUtf8((const char *)value); + ++ // Patch: Enable Open Sans Semibold font family reading. ++ if (familyName == QLatin1String("Open Sans")) { ++ FcChar8 *styl = 0; ++ if (FcPatternGetString(pattern, FC_STYLE, 0, &styl) == FcResultMatch) { ++ QString style = QString::fromUtf8(reinterpret_cast(styl)); ++ if (style == QLatin1String("Semibold")) { ++ familyName.append(QChar(QChar::Space)).append(style); ++ } ++ } ++ } ++ + slant_value = FC_SLANT_ROMAN; + weight_value = FC_WEIGHT_REGULAR; + spacing_value = FC_PROPORTIONAL; +@@ -718,7 +729,19 @@ QStringList QFontconfigDatabase::fallbacksForFamily(const QString &family, QFont + if (FcPatternGetString(fontSet->fonts[i], FC_FAMILY, 0, &value) != FcResultMatch) + continue; + // capitalize(value); +- const QString familyName = QString::fromUtf8((const char *)value); ++ ++ // Patch: Enable Open Sans Semibold font family reading. ++ QString familyName = QString::fromUtf8((const char *)value); ++ if (familyName == QLatin1String("Open Sans")) { ++ FcChar8 *styl = 0; ++ if (FcPatternGetString(fontSet->fonts[i], FC_STYLE, 0, &styl) == FcResultMatch) { ++ QString style = QString::fromUtf8(reinterpret_cast(styl)); ++ if (style == QLatin1String("Semibold")) { ++ familyName.append(QChar(QChar::Space)).append(style); ++ } ++ } ++ } ++ + const QString familyNameCF = familyName.toCaseFolded(); + if (!duplicates.contains(familyNameCF)) { + fallbackFamilies << familyName; +@@ -784,6 +807,18 @@ QStringList QFontconfigDatabase::addApplicationFont(const QByteArray &fontData, + FcChar8 *fam = 0; + if (FcPatternGetString(pattern, FC_FAMILY, 0, &fam) == FcResultMatch) { + QString family = QString::fromUtf8(reinterpret_cast(fam)); ++ ++ // Patch: Enable Open Sans Semibold font family reading. ++ if (family == QLatin1String("Open Sans")) { ++ FcChar8 *styl = 0; ++ if (FcPatternGetString(pattern, FC_STYLE, 0, &styl) == FcResultMatch) { ++ QString style = QString::fromUtf8(reinterpret_cast(styl)); ++ if (style == QLatin1String("Semibold")) { ++ family.append(QChar(QChar::Space)).append(style); ++ } ++ } ++ } ++ + families << family; + } + populateFromPattern(pattern); +diff --git a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm b/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm +index 566abf2126..5c5fde9813 100644 +--- a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm ++++ b/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm +@@ -265,6 +265,13 @@ static void getFontDescription(CTFontDescriptorRef font, FontDescription *fd) + + fd->foundryName = QStringLiteral("CoreText"); + fd->familyName = (CFStringRef) CTFontDescriptorCopyAttribute(font, kCTFontFamilyNameAttribute); ++ ++ // Patch: Enable Open Sans Semibold font family reading. ++ QCFString _displayName = (CFStringRef) CTFontDescriptorCopyAttribute(font, kCTFontDisplayNameAttribute); ++ if (_displayName == QStringLiteral("Open Sans Semibold")) { ++ fd->familyName = _displayName; ++ } ++ + fd->styleName = (CFStringRef)CTFontDescriptorCopyAttribute(font, kCTFontStyleNameAttribute); + fd->weight = QFont::Normal; + fd->style = QFont::StyleNormal; +@@ -300,9 +307,10 @@ static void getFontDescription(CTFontDescriptorRef font, FontDescription *fd) + + if (styles) { + if (CFNumberRef weightValue = (CFNumberRef) CFDictionaryGetValue(styles, kCTFontWeightTrait)) { +- float normalizedWeight; +- if (CFNumberGetValue(weightValue, kCFNumberFloatType, &normalizedWeight)) +- fd->weight = QCoreTextFontEngine::qtWeightFromCFWeight(normalizedWeight); ++ // Patch: backport bugfix from 'b64ea4a3ab' commit. ++ double normalizedWeight; ++ if (CFNumberGetValue(weightValue, kCFNumberFloat64Type, &normalizedWeight)) ++ fd->weight = QCoreTextFontEngine::qtWeightFromCFWeight(float(normalizedWeight)); + } + if (CFNumberRef italic = (CFNumberRef) CFDictionaryGetValue(styles, kCTFontSlantTrait)) { + double d; +diff --git a/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm b/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm +index 7b459584ea..2ed2fd9b3b 100644 +--- a/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm ++++ b/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm +@@ -764,7 +764,8 @@ void QCoreTextFontEngine::getUnscaledGlyph(glyph_t glyph, QPainterPath *path, gl + + QFixed QCoreTextFontEngine::emSquareSize() const + { +- return QFixed::QFixed(int(CTFontGetUnitsPerEm(ctfont))); ++ // Patch: Fix build for Xcode 9.3.1. ++ return QFixed(int(CTFontGetUnitsPerEm(ctfont))); + } + + QFontEngine *QCoreTextFontEngine::cloneWithSize(qreal pixelSize) const +diff --git a/src/plugins/platforminputcontexts/compose/compose.pro b/src/plugins/platforminputcontexts/compose/compose.pro +index 86bdd4729b..9b9c8ded08 100644 +--- a/src/plugins/platforminputcontexts/compose/compose.pro ++++ b/src/plugins/platforminputcontexts/compose/compose.pro +@@ -15,7 +15,8 @@ HEADERS += $$PWD/qcomposeplatforminputcontext.h \ + contains(QT_CONFIG, xkbcommon-qt): { + # dont't need x11 dependency for compose key plugin + QT_CONFIG -= use-xkbcommon-x11support +- include(../../../3rdparty/xkbcommon.pri) ++ # Patch: Adding fcitx input context plugin to our static build. ++ #include(../../../3rdparty/xkbcommon.pri) + } else { + LIBS += $$QMAKE_LIBS_XKBCOMMON + QMAKE_CXXFLAGS += $$QMAKE_CFLAGS_XKBCOMMON +diff --git a/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontext.cpp b/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontext.cpp +index d1bea9af23..36a15a6473 100644 +--- a/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontext.cpp ++++ b/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontext.cpp +@@ -232,6 +232,12 @@ bool QComposeInputContext::checkComposeTable() + + void QComposeInputContext::commitText(uint character) const + { ++ // Patch: Crash fix when not focused widget still receives input events. ++ if (!m_focusObject) { ++ qWarning("QComposeInputContext::commitText: m_focusObject == nullptr, cannot commit text"); ++ return; ++ } ++ + QInputMethodEvent event; + event.setCommitString(QChar(character)); + QCoreApplication::sendEvent(m_focusObject, &event); +diff --git a/src/plugins/platforminputcontexts/platforminputcontexts.pro b/src/plugins/platforminputcontexts/platforminputcontexts.pro +index faea54b874..fe4a837511 100644 +--- a/src/plugins/platforminputcontexts/platforminputcontexts.pro ++++ b/src/plugins/platforminputcontexts/platforminputcontexts.pro +@@ -1,7 +1,8 @@ + TEMPLATE = subdirs + + qtHaveModule(dbus) { +-!mac:!win32:SUBDIRS += ibus ++# Patch: Adding fcitx/hime/nimf input context plugin to our static build. ++!mac:!win32:SUBDIRS += ibus fcitx hime nimf + } + + contains(QT_CONFIG, xcb-plugin): SUBDIRS += compose +diff --git a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm +index caa8884661..9dc3bc1661 100644 +--- a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm ++++ b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm +@@ -210,7 +210,8 @@ QT_END_NAMESPACE + if (reflectionDelegate) { + if ([reflectionDelegate respondsToSelector:@selector(applicationShouldTerminate:)]) + return [reflectionDelegate applicationShouldTerminate:sender]; +- return NSTerminateNow; ++ // Patch: Don't terminate if reflectionDelegate does not respond to that selector, just use the default. ++ //return NSTerminateNow; + } + + if ([self canQuit]) { +@@ -287,11 +288,15 @@ QT_END_NAMESPACE + + - (void)applicationDidFinishLaunching:(NSNotification *)aNotification + { ++ // Patch: We need to catch that notification in delegate. ++ if (reflectionDelegate ++ && [reflectionDelegate respondsToSelector:@selector(applicationDidFinishLaunching:)]) ++ [reflectionDelegate applicationDidFinishLaunching:aNotification]; ++ + Q_UNUSED(aNotification); + inLaunch = false; + // qt_release_apple_event_handler(); + +- + // Insert code here to initialize your application + } + +diff --git a/src/plugins/platforms/cocoa/qcocoabackingstore.h b/src/plugins/platforms/cocoa/qcocoabackingstore.h +index 934f68ad18..3ece6984ac 100644 +--- a/src/plugins/platforms/cocoa/qcocoabackingstore.h ++++ b/src/plugins/platforms/cocoa/qcocoabackingstore.h +@@ -64,6 +64,9 @@ public: + private: + QImage m_qImage; + QSize m_requestedSize; ++ ++ // Patch: Optimize redraw - don't clear image if it will be fully redrawn. ++ bool m_qImageNeedsClear; + }; + + QT_END_NAMESPACE +diff --git a/src/plugins/platforms/cocoa/qcocoabackingstore.mm b/src/plugins/platforms/cocoa/qcocoabackingstore.mm +index ca92103826..f27ea15bad 100644 +--- a/src/plugins/platforms/cocoa/qcocoabackingstore.mm ++++ b/src/plugins/platforms/cocoa/qcocoabackingstore.mm +@@ -38,7 +38,8 @@ + QT_BEGIN_NAMESPACE + + QCocoaBackingStore::QCocoaBackingStore(QWindow *window) +- : QPlatformBackingStore(window) ++ // Patch: Optimize redraw - don't clear image if it will be fully redrawn. ++ : QPlatformBackingStore(window), m_qImageNeedsClear(false) + { + } + +@@ -59,9 +60,12 @@ QPaintDevice *QCocoaBackingStore::paintDevice() + if (m_qImage.size() != effectiveBufferSize) { + QImage::Format format = (window()->format().hasAlpha() || cocoaWindow->m_drawContentBorderGradient) + ? QImage::Format_ARGB32_Premultiplied : QImage::Format_RGB32; ++ ++ // Patch: Optimize redraw - don't clear image if it will be fully redrawn. ++ m_qImageNeedsClear = window()->requestedFormat().hasAlpha() || cocoaWindow->m_drawContentBorderGradient; + m_qImage = QImage(effectiveBufferSize, format); + m_qImage.setDevicePixelRatio(windowDevicePixelRatio); +- if (format == QImage::Format_ARGB32_Premultiplied) ++ if (m_qImageNeedsClear) + m_qImage.fill(Qt::transparent); + } + return &m_qImage; +@@ -100,7 +104,8 @@ bool QCocoaBackingStore::scroll(const QRegion &area, int dx, int dy) + + void QCocoaBackingStore::beginPaint(const QRegion ®ion) + { +- if (m_qImage.hasAlphaChannel()) { ++ // Patch: Optimize redraw - don't clear image if it will be fully redrawn. ++ if (m_qImageNeedsClear && m_qImage.hasAlphaChannel()) { + QPainter p(&m_qImage); + p.setCompositionMode(QPainter::CompositionMode_Source); + const QVector rects = region.rects(); +diff --git a/src/plugins/platforms/cocoa/qcocoahelpers.mm b/src/plugins/platforms/cocoa/qcocoahelpers.mm +index 058209da7e..6af61e7dab 100644 +--- a/src/plugins/platforms/cocoa/qcocoahelpers.mm ++++ b/src/plugins/platforms/cocoa/qcocoahelpers.mm +@@ -546,9 +546,9 @@ OSStatus qt_mac_drawCGImage(CGContextRef inContext, const CGRect *inBounds, CGIm + // Verbatim copy if HIViewDrawCGImage (as shown on Carbon-Dev) + OSStatus err = noErr; + +- require_action(inContext != NULL, InvalidContext, err = paramErr); +- require_action(inBounds != NULL, InvalidBounds, err = paramErr); +- require_action(inImage != NULL, InvalidImage, err = paramErr); ++// require_action(inContext != NULL, InvalidContext, err = paramErr); ++// require_action(inBounds != NULL, InvalidBounds, err = paramErr); ++// require_action(inImage != NULL, InvalidImage, err = paramErr); + + CGContextSaveGState( inContext ); + CGContextTranslateCTM (inContext, 0, inBounds->origin.y + CGRectGetMaxY(*inBounds)); +@@ -557,9 +557,9 @@ OSStatus qt_mac_drawCGImage(CGContextRef inContext, const CGRect *inBounds, CGIm + CGContextDrawImage(inContext, *inBounds, inImage); + + CGContextRestoreGState(inContext); +-InvalidImage: +-InvalidBounds: +-InvalidContext: ++//InvalidImage: ++//InvalidBounds: ++//InvalidContext: + return err; + } + +diff --git a/src/plugins/platforms/cocoa/qcocoakeymapper.mm b/src/plugins/platforms/cocoa/qcocoakeymapper.mm +index c2d206fb45..9b9739862d 100644 +--- a/src/plugins/platforms/cocoa/qcocoakeymapper.mm ++++ b/src/plugins/platforms/cocoa/qcocoakeymapper.mm +@@ -384,6 +384,12 @@ bool QCocoaKeyMapper::updateKeyboard() + keyboardInputLocale = QLocale::c(); + keyboardInputDirection = Qt::LeftToRight; + } ++ ++ // Patch: Fix layout-independent global shortcuts. ++ const auto newMode = keyboard_mode; ++ deleteLayouts(); ++ keyboard_mode = newMode; ++ + return true; + } + +@@ -466,7 +472,8 @@ QList QCocoaKeyMapper::possibleKeys(const QKeyEvent *event) const + Qt::KeyboardModifiers neededMods = ModsTbl[i]; + int key = kbItem->qtKey[i]; + if (key && key != baseKey && ((keyMods & neededMods) == neededMods)) { +- ret << int(key + (keyMods & ~neededMods)); ++ // Patch: Fix layout-independent global shortcuts. ++ ret << int(key + neededMods); + } + } + return ret; +diff --git a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm +index 8152c57ffd..87ba2f3f72 100644 +--- a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm ++++ b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm +@@ -94,6 +94,8 @@ QT_USE_NAMESPACE + QCocoaSystemTrayIcon *systray; + NSStatusItem *item; + QCocoaMenu *menu; ++ // Patch: Create a rich os x tray icon (pixel-perfect, theme switching). ++ bool menuVisible, iconSelected; + QIcon icon; + QT_MANGLE_NAMESPACE(QNSImageView) *imageCell; + } +@@ -197,7 +199,9 @@ void QCocoaSystemTrayIcon::updateIcon(const QIcon &icon) + // (device independent pixels). The menu height on past and + // current OS X versions is 22 points. Provide some future-proofing + // by deriving the icon height from the menu height. +- const int padding = 4; ++ ++ // Patch: Create a rich os x tray icon (pixel-perfect, theme switching). ++ const int padding = 0; + const int menuHeight = [[NSStatusBar systemStatusBar] thickness]; + const int maxImageHeight = menuHeight - padding; + +@@ -207,8 +211,11 @@ void QCocoaSystemTrayIcon::updateIcon(const QIcon &icon) + // devicePixelRatio for the "best" screen on the system. + qreal devicePixelRatio = qApp->devicePixelRatio(); + const int maxPixmapHeight = maxImageHeight * devicePixelRatio; ++ ++ // Patch: Create a rich os x tray icon (pixel-perfect, theme switching). ++ const QIcon::Mode mode = m_sys->item->iconSelected ? QIcon::Selected : QIcon::Normal; + QSize selectedSize; +- Q_FOREACH (const QSize& size, sortByHeight(icon.availableSizes())) { ++ Q_FOREACH (const QSize& size, sortByHeight(icon.availableSizes(mode))) { + // Select a pixmap based on the height. We want the largest pixmap + // with a height smaller or equal to maxPixmapHeight. The pixmap + // may rectangular; assume it has a reasonable size. If there is +@@ -224,9 +231,9 @@ void QCocoaSystemTrayIcon::updateIcon(const QIcon &icon) + + // Handle SVG icons, which do not return anything for availableSizes(). + if (!selectedSize.isValid()) +- selectedSize = icon.actualSize(QSize(maxPixmapHeight, maxPixmapHeight)); ++ selectedSize = icon.actualSize(QSize(maxPixmapHeight, maxPixmapHeight), mode); + +- QPixmap pixmap = icon.pixmap(selectedSize); ++ QPixmap pixmap = icon.pixmap(selectedSize, mode); + + // Draw a low-resolution icon if there is not enough pixels for a retina + // icon. This prevents showing a small icon on retina displays. +@@ -374,6 +381,11 @@ QT_END_NAMESPACE + Q_UNUSED(notification); + down = NO; + ++ // Patch: Create a rich os x tray icon (pixel-perfect, theme switching). ++ parent->iconSelected = false; ++ parent->systray->updateIcon(parent->icon); ++ parent->menuVisible = false; ++ + [self setNeedsDisplay:YES]; + } + +@@ -383,6 +395,10 @@ QT_END_NAMESPACE + int clickCount = [mouseEvent clickCount]; + [self setNeedsDisplay:YES]; + ++ // Patch: Create a rich os x tray icon (pixel-perfect, theme switching). ++ parent->iconSelected = (clickCount != 2) && parent->menu; ++ parent->systray->updateIcon(parent->icon); ++ + if (clickCount == 2) { + [self menuTrackingDone:nil]; + [parent doubleClickSelector:self]; +@@ -399,6 +415,11 @@ QT_END_NAMESPACE + -(void)mouseUp:(NSEvent *)mouseEvent + { + Q_UNUSED(mouseEvent); ++ ++ // Patch: Create a rich os x tray icon (pixel-perfect, theme switching). ++ parent->iconSelected = false; ++ parent->systray->updateIcon(parent->icon); ++ + [self menuTrackingDone:nil]; + } + +@@ -410,6 +431,11 @@ QT_END_NAMESPACE + -(void)rightMouseUp:(NSEvent *)mouseEvent + { + Q_UNUSED(mouseEvent); ++ ++ // Patch: Create a rich os x tray icon (pixel-perfect, theme switching). ++ parent->iconSelected = false; ++ parent->systray->updateIcon(parent->icon); ++ + [self menuTrackingDone:nil]; + } + +@@ -425,7 +451,8 @@ QT_END_NAMESPACE + } + + -(void)drawRect:(NSRect)rect { +- [[parent item] drawStatusBarBackgroundInRect:rect withHighlight:down]; ++ // Patch: Create a rich os x tray icon (pixel-perfect, theme switching). ++ [[parent item] drawStatusBarBackgroundInRect:rect withHighlight:parent->menu ? down : NO]; + [super drawRect:rect]; + } + @end +@@ -438,6 +465,10 @@ QT_END_NAMESPACE + if (self) { + item = [[[NSStatusBar systemStatusBar] statusItemWithLength:NSSquareStatusItemLength] retain]; + menu = 0; ++ ++ // Patch: Create a rich os x tray icon (pixel-perfect, theme switching). ++ menuVisible = false; ++ + systray = sys; + imageCell = [[QNSImageView alloc] initWithParent:self]; + [item setView: imageCell]; +@@ -448,6 +479,11 @@ QT_END_NAMESPACE + -(void)dealloc { + [[NSStatusBar systemStatusBar] removeStatusItem:item]; + [[NSNotificationCenter defaultCenter] removeObserver:imageCell]; ++ ++ // Patch: Fix crash in macOS 10.14. ++ // Somehow item and imageCell are retained and attempt to be drawn if left in view. ++ [item setView: nil]; ++ + [imageCell release]; + [item release]; + [super dealloc]; +@@ -482,6 +518,10 @@ QT_END_NAMESPACE + selector:@selector(menuTrackingDone:) + name:NSMenuDidEndTrackingNotification + object:m]; ++ ++ // Patch: Create a rich os x tray icon (pixel-perfect, theme switching). ++ menuVisible = true; ++ + [item popUpStatusItemMenu: m]; + } + } +diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm +index c0d5904367..f3c2047196 100644 +--- a/src/plugins/platforms/cocoa/qcocoawindow.mm ++++ b/src/plugins/platforms/cocoa/qcocoawindow.mm +@@ -141,7 +141,8 @@ static bool isMouseEvent(NSEvent *ev) + if (!self.window.delegate) + return; // Already detached, pending NSAppKitDefined event + +- if (pw && pw->frameStrutEventsEnabled() && isMouseEvent(theEvent)) { ++ // Patch: Fix restore after minimize or close by window buttons. ++ if (pw && pw->frameStrutEventsEnabled() && pw->m_synchedWindowState != Qt::WindowMinimized && pw->m_isExposed && isMouseEvent(theEvent)) { + NSPoint loc = [theEvent locationInWindow]; + NSRect windowFrame = [self.window convertRectFromScreen:[self.window frame]]; + NSRect contentFrame = [[self.window contentView] frame]; +@@ -811,6 +812,16 @@ NSUInteger QCocoaWindow::windowStyleMask(Qt::WindowFlags flags) + { + Qt::WindowType type = static_cast(int(flags & Qt::WindowType_Mask)); + NSInteger styleMask = NSBorderlessWindowMask; ++ ++ // Patch: allow creating panels floating on all spaces in macOS. ++ // If you call "setCollectionBehavior:NSWindowCollectionBehaviorFullScreenAuxiliary" before ++ // setting the "NSNonactivatingPanelMask" bit in the style mask it won't work after that. ++ // So we need a way to set that bit before Qt sets collection behavior the way it does. ++ QVariant nonactivatingPanelMask = window()->property("_td_macNonactivatingPanelMask"); ++ if (nonactivatingPanelMask.isValid() && nonactivatingPanelMask.toBool()) { ++ styleMask |= NSNonactivatingPanelMask; ++ } ++ + if (flags & Qt::FramelessWindowHint) + return styleMask; + if ((type & Qt::Popup) == Qt::Popup) { +@@ -943,6 +954,19 @@ void QCocoaWindow::setWindowFilePath(const QString &filePath) + [m_nsWindow setRepresentedFilename: fi.exists() ? QCFString::toNSString(filePath) : @""]; + } + ++// Patch: Create a good os x window icon (pixel-perfect). ++namespace { ++ ++qreal getDevicePixelRatio() { ++ qreal result = 1.0; ++ foreach (QScreen *screen, QGuiApplication::screens()) { ++ result = qMax(result, screen->devicePixelRatio()); ++ } ++ return result; ++} ++ ++} // namespace ++ + void QCocoaWindow::setWindowIcon(const QIcon &icon) + { + QMacAutoReleasePool pool; +@@ -958,7 +982,9 @@ void QCocoaWindow::setWindowIcon(const QIcon &icon) + if (icon.isNull()) { + [iconButton setImage:nil]; + } else { +- QPixmap pixmap = icon.pixmap(QSize(22, 22)); ++ // Patch: Create a good os x window icon (pixel-perfect). ++ CGFloat hgt = 16. * getDevicePixelRatio(); ++ QPixmap pixmap = icon.pixmap(QSize(hgt, hgt)); + NSImage *image = static_cast(qt_mac_create_nsimage(pixmap)); + [iconButton setImage:image]; + [image release]; +diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm +index c67bcfd23b..6a60670aee 100644 +--- a/src/plugins/platforms/cocoa/qnsview.mm ++++ b/src/plugins/platforms/cocoa/qnsview.mm +@@ -647,6 +647,12 @@ QT_WARNING_POP + [self invalidateWindowShadowIfNeeded]; + } + ++- (void)viewDidChangeBackingProperties ++{ ++ if (self.layer) ++ self.layer.contentsScale = self.window.backingScaleFactor; ++} ++ + - (BOOL) isFlipped + { + return YES; +@@ -1431,7 +1437,9 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent) + #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_8 + if (QSysInfo::QSysInfo::MacintoshVersion >= QSysInfo::MV_10_8) { + // On 10.8 and above, MayBegin is likely to happen. We treat it the same as an actual begin. +- if (phase == NSEventPhaseMayBegin) { ++ ++ // Patch: Fix actual begin handle of swipe on trackpad. ++ if (phase == NSEventPhaseMayBegin || phase == NSEventPhaseBegan) { + m_scrolling = true; + ph = Qt::ScrollBegin; + } +@@ -1496,14 +1504,14 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent) + quint32 nativeVirtualKey = [nsevent keyCode]; + + QChar ch = QChar::ReplacementCharacter; +- int keyCode = Qt::Key_unknown; +- if ([characters length] != 0) { +- if (((modifiers & Qt::MetaModifier) || (modifiers & Qt::AltModifier)) && ([charactersIgnoringModifiers length] != 0)) +- ch = QChar([charactersIgnoringModifiers characterAtIndex:0]); +- else +- ch = QChar([characters characterAtIndex:0]); +- keyCode = [self convertKeyCode:ch]; +- } ++ ++ // Patch: Fix Alt+.. shortcuts in OS X. See https://bugreports.qt.io/browse/QTBUG-42584 at the end. ++ if ([characters length] != 0) ++ ch = QChar([characters characterAtIndex:0]); ++ else if ([charactersIgnoringModifiers length] != 0 && ((modifiers & Qt::MetaModifier) || (modifiers & Qt::AltModifier))) ++ ch = QChar([charactersIgnoringModifiers characterAtIndex:0]); ++ ++ int keyCode = [self convertKeyCode:ch]; + + // we will send a key event unless the input method sets m_sendKeyEvent to false + m_sendKeyEvent = true; +@@ -1569,6 +1577,23 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent) + [self handleKeyEvent:nsevent eventType:int(QEvent::KeyRelease)]; + } + ++// Patch: Enable Ctrl+Tab and Ctrl+Shift+Tab / Ctrl+Backtab handle in-app. ++- (BOOL)performKeyEquivalent:(NSEvent *)nsevent ++{ ++ NSString *chars = [nsevent charactersIgnoringModifiers]; ++ ++ if ([nsevent type] == NSKeyDown && [chars length] > 0) { ++ QChar ch = [chars characterAtIndex:0]; ++ Qt::Key qtKey = qt_mac_cocoaKey2QtKey(ch); ++ if ([nsevent modifierFlags] & NSControlKeyMask ++ && (qtKey == Qt::Key_Tab || qtKey == Qt::Key_Backtab)) { ++ [self handleKeyEvent:nsevent eventType:int(QEvent::KeyPress)]; ++ return YES; ++ } ++ } ++ return [super performKeyEquivalent:nsevent]; ++} ++ + - (void)cancelOperation:(id)sender + { + Q_UNUSED(sender); +@@ -1981,6 +2006,10 @@ static QPoint mapWindowCoordinates(QWindow *source, QWindow *target, QPoint poin + // change the cursor + [nativeCursor set]; + ++ // Patch: Backport a fix from cd08753d3e. Starting with macOS Mojave this requires accessibility access. ++ if (QSysInfo::macVersion() >= Q_MV_OSX(10, 14)) ++ return; ++ + // Make sure the cursor is updated correctly if the mouse does not move and window is under cursor + // by creating a fake move event + if (m_updatingDrag) +diff --git a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp +index 94bb71e429..16ab51e166 100644 +--- a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp ++++ b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp +@@ -716,12 +716,20 @@ public: + void setSelectedFiles(const QList &); + QString selectedFile() const; + ++ // Patch: Adding select-by-url for Windows file dialog. ++ void setSelectedRemoteContent(const QByteArray &); ++ QByteArray selectedRemoteContent() const; ++ + private: + class Data : public QSharedData { + public: + QUrl directory; + QString selectedNameFilter; + QList selectedFiles; ++ ++ // Patch: Adding select-by-url for Windows file dialog. ++ QByteArray selectedRemoteContent; ++ + QMutex mutex; + }; + QExplicitlySharedDataPointer m_data; +@@ -775,6 +783,21 @@ inline void QWindowsFileDialogSharedData::setSelectedFiles(const QList &ur + m_data->selectedFiles = urls; + } + ++// Patch: Adding select-by-url for Windows file dialog. ++inline QByteArray QWindowsFileDialogSharedData::selectedRemoteContent() const ++{ ++ m_data->mutex.lock(); ++ const QByteArray result = m_data->selectedRemoteContent; ++ m_data->mutex.unlock(); ++ return result; ++} ++ ++inline void QWindowsFileDialogSharedData::setSelectedRemoteContent(const QByteArray &c) ++{ ++ QMutexLocker(&m_data->mutex); ++ m_data->selectedRemoteContent = c; ++} ++ + inline void QWindowsFileDialogSharedData::fromOptions(const QSharedPointer &o) + { + QMutexLocker locker(&m_data->mutex); +@@ -899,6 +922,9 @@ public: + // example by appended default suffixes, etc. + virtual QList dialogResult() const = 0; + ++ // Patch: Adding select-by-url for Windows file dialog. ++ virtual QByteArray dialogRemoteContent() const { return QByteArray(); } ++ + inline void onFolderChange(IShellItem *); + inline void onSelectionChange(); + inline void onTypeChange(); +@@ -1338,7 +1364,14 @@ void QWindowsNativeFileDialogBase::selectFile(const QString &fileName) const + // Hack to prevent CLSIDs from being set as file name due to + // QFileDialogPrivate::initialSelection() being QString-based. + if (!isClsid(fileName)) +- m_fileDialog->SetFileName((wchar_t*)fileName.utf16()); ++ // Patch: Fix handle of full fileName. ++ { ++ QString file = QDir::toNativeSeparators(fileName); ++ int lastBackSlash = file.lastIndexOf(QChar::fromLatin1('\\')); ++ if (lastBackSlash >= 0) ++ file = file.mid(lastBackSlash + 1); ++ m_fileDialog->SetFileName((wchar_t*)file.utf16());; ++ } + } + + // Return the index of the selected filter, accounting for QFileDialog +@@ -1408,6 +1441,10 @@ bool QWindowsNativeFileDialogBase::onFileOk() + { + // Store selected files as GetResults() returns invalid data after the dialog closes. + m_data.setSelectedFiles(dialogResult()); ++ ++ // Patch: Adding select-by-url for Windows file dialog. ++ m_data.setSelectedRemoteContent(dialogRemoteContent()); ++ + return true; + } + +@@ -1542,6 +1579,9 @@ public: + QList selectedFiles() const Q_DECL_OVERRIDE; + QList dialogResult() const Q_DECL_OVERRIDE; + ++ // Patch: Adding select-by-url for Windows file dialog. ++ QByteArray dialogRemoteContent() const Q_DECL_OVERRIDE; ++ + private: + inline IFileOpenDialog *openFileDialog() const + { return static_cast(fileDialog()); } +@@ -1556,6 +1596,62 @@ QList QWindowsNativeOpenFileDialog::dialogResult() const + return result; + } + ++// Patch: Adding select-by-url for Windows file dialog. ++QByteArray QWindowsNativeOpenFileDialog::dialogRemoteContent() const ++{ ++ QByteArray result; ++ IShellItemArray *items = 0; ++ if (FAILED(openFileDialog()->GetResults(&items)) || !items) ++ return result; ++ DWORD itemCount = 0; ++ if (FAILED(items->GetCount(&itemCount)) || !itemCount) ++ return result; ++ for (DWORD i = 0; i < itemCount; ++i) ++ { ++ IShellItem *item = 0; ++ if (SUCCEEDED(items->GetItemAt(i, &item))) { ++ SFGAOF attributes = 0; ++ // Check whether it has a file system representation? ++ if (FAILED(item->GetAttributes(SFGAO_FILESYSTEM, &attributes)) || (attributes & SFGAO_FILESYSTEM)) ++ { ++ LPWSTR name = 0; ++ if (SUCCEEDED(item->GetDisplayName(SIGDN_FILESYSPATH, &name))) ++ { ++ CoTaskMemFree(name); ++ continue; ++ } ++ } ++ if (FAILED(item->GetAttributes(SFGAO_STREAM, &attributes)) || !(attributes & SFGAO_STREAM)) ++ continue; ++ ++ IBindCtx *bind = 0; ++ if (FAILED(CreateBindCtx(0, &bind))) ++ continue; ++ ++ IStream *stream = 0; ++ if (FAILED(item->BindToHandler(bind, BHID_Stream, IID_IStream, reinterpret_cast(&stream)))) ++ continue; ++ ++ STATSTG stat = { 0 }; ++ if (FAILED(stream->Stat(&stat, STATFLAG_NONAME)) || !stat.cbSize.QuadPart) ++ continue; ++ ++ quint64 fullSize = stat.cbSize.QuadPart; ++ if (fullSize <= 64 * 1024 * 1024) ++ { ++ result.resize(fullSize); ++ ULONG read = 0; ++ HRESULT r = stream->Read(result.data(), fullSize, &read); ++ if (r == S_FALSE || r == S_OK) ++ return result; ++ ++ result.clear(); ++ } ++ } ++ } ++ return result; ++} ++ + QList QWindowsNativeOpenFileDialog::selectedFiles() const + { + QList result; +@@ -1614,6 +1710,10 @@ public: + virtual QUrl directory() const Q_DECL_OVERRIDE; + virtual void selectFile(const QUrl &filename) Q_DECL_OVERRIDE; + virtual QList selectedFiles() const Q_DECL_OVERRIDE; ++ ++ // Patch: Adding select-by-url for Windows file dialog. ++ virtual QByteArray selectedRemoteContent() const Q_DECL_OVERRIDE; ++ + virtual void setFilter() Q_DECL_OVERRIDE; + virtual void selectNameFilter(const QString &filter) Q_DECL_OVERRIDE; + virtual QString selectedNameFilter() const Q_DECL_OVERRIDE; +@@ -1707,6 +1807,12 @@ QList QWindowsFileDialogHelper::selectedFiles() const + return m_data.selectedFiles(); + } + ++// Patch: Adding select-by-url for Windows file dialog. ++QByteArray QWindowsFileDialogHelper::selectedRemoteContent() const ++{ ++ return m_data.selectedRemoteContent(); ++} ++ + void QWindowsFileDialogHelper::setFilter() + { + qCDebug(lcQpaDialogs) << __FUNCTION__; +@@ -1996,6 +2102,10 @@ public: + QUrl directory() const Q_DECL_OVERRIDE; + void selectFile(const QUrl &url) Q_DECL_OVERRIDE; + QList selectedFiles() const Q_DECL_OVERRIDE; ++ ++ // Patch: Adding select-by-url for Windows file dialog. ++ QByteArray selectedRemoteContent() const Q_DECL_OVERRIDE; ++ + void setFilter() Q_DECL_OVERRIDE {} + void selectNameFilter(const QString &) Q_DECL_OVERRIDE; + QString selectedNameFilter() const Q_DECL_OVERRIDE; +@@ -2039,6 +2149,12 @@ QList QWindowsXpFileDialogHelper::selectedFiles() const + return m_data.selectedFiles(); + } + ++// Patch: Adding select-by-url for Windows file dialog. ++QByteArray QWindowsXpFileDialogHelper::selectedRemoteContent() const ++{ ++ return m_data.selectedRemoteContent(); ++} ++ + void QWindowsXpFileDialogHelper::selectNameFilter(const QString &f) + { + m_data.setSelectedNameFilter(f); // Dialog cannot be updated at run-time. +diff --git a/src/plugins/platforms/windows/qwindowskeymapper.cpp b/src/plugins/platforms/windows/qwindowskeymapper.cpp +index 1e58b9b3d4..1741c21a1c 100644 +--- a/src/plugins/platforms/windows/qwindowskeymapper.cpp ++++ b/src/plugins/platforms/windows/qwindowskeymapper.cpp +@@ -1268,6 +1268,10 @@ QList QWindowsKeyMapper::possibleKeys(const QKeyEvent *e) const + if (nativeVirtualKey > 255) + return result; + ++ // Patch: This must not happen, but there are crash reports on the next line. ++ if (e->nativeVirtualKey() > 0xFF) ++ return result; ++ + const KeyboardLayoutItem &kbItem = keyLayout[nativeVirtualKey]; + if (!kbItem.exists) + return result; +diff --git a/src/plugins/platforms/windows/qwindowsservices.cpp b/src/plugins/platforms/windows/qwindowsservices.cpp +index 1d23a9d9b9..640cd426ed 100644 +--- a/src/plugins/platforms/windows/qwindowsservices.cpp ++++ b/src/plugins/platforms/windows/qwindowsservices.cpp +@@ -127,6 +127,10 @@ static inline bool launchMail(const QUrl &url) + command.prepend(doubleQuote); + } + } ++ ++ // Patch: Fix mail launch if no param is expected in this command. ++ if (command.indexOf(QStringLiteral("%1")) < 0) return false; ++ + // Pass the url as the parameter. Should use QProcess::startDetached(), + // but that cannot handle a Windows command line [yet]. + command.replace(QStringLiteral("%1"), url.toString(QUrl::FullyEncoded)); +diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp +index b38d7c29ae..34f19c4efa 100644 +--- a/src/plugins/platforms/windows/qwindowswindow.cpp ++++ b/src/plugins/platforms/windows/qwindowswindow.cpp +@@ -1020,7 +1020,8 @@ void QWindowsWindow::destroyWindow() + // Clear any transient child relationships as Windows will otherwise destroy them (QTBUG-35499, QTBUG-36666) + if (QWindow *transientChild = findTransientChild(window())) + if (QWindowsWindow *tw = QWindowsWindow::baseWindowOf(transientChild)) +- tw->updateTransientParent(); ++ // Patch: Fix possibility of add / remove taskbar icon of the window. ++ tw->clearTransientParent(); + QWindowsContext *context = QWindowsContext::instance(); + if (context->windowUnderMouse() == window()) + context->clearWindowUnderMouse(); +@@ -1235,6 +1236,21 @@ void QWindowsWindow::updateTransientParent() const + if (const QWindowsWindow *tw = QWindowsWindow::baseWindowOf(tp)) + if (!tw->testFlag(WithinDestroy)) // Prevent destruction by parent window (QTBUG-35499, QTBUG-36666) + newTransientParent = tw->handle(); ++ // Patch: Fix possibility of add / remove taskbar icon of the window. ++ if (newTransientParent && newTransientParent != oldTransientParent) ++ SetWindowLongPtr(m_data.hwnd, GWL_HWNDPARENT, (LONG_PTR)newTransientParent); ++#endif // !Q_OS_WINCE ++} ++ ++// Patch: Fix possibility of add / remove taskbar icon of the window. ++void QWindowsWindow::clearTransientParent() const ++{ ++#ifndef Q_OS_WINCE ++ if (window()->type() == Qt::Popup) ++ return; // QTBUG-34503, // a popup stays on top, no parent, see also WindowCreationData::fromWindow(). ++ // Update transient parent. ++ const HWND oldTransientParent = transientParentHwnd(m_data.hwnd); ++ HWND newTransientParent = 0; + if (newTransientParent != oldTransientParent) + SetWindowLongPtr(m_data.hwnd, GWL_HWNDPARENT, (LONG_PTR)newTransientParent); + #endif // !Q_OS_WINCE +@@ -1448,10 +1464,14 @@ void QWindowsWindow::handleResized(int wParam) + handleGeometryChange(); + break; + case SIZE_RESTORED: +- if (isFullScreen_sys()) +- handleWindowStateChange(Qt::WindowFullScreen); +- else if (m_windowState != Qt::WindowNoState && !testFlag(MaximizeToFullScreen)) ++ // Patch: When resolution is changed for a frameless fullscreen widget ++ // handleWindowStateChange call prevents correct geometry get in handleGeometryChange(). ++ if (isFullScreen_sys()) { ++ if (m_windowState != Qt::WindowFullScreen) ++ handleWindowStateChange(Qt::WindowFullScreen); ++ } else if (m_windowState != Qt::WindowNoState && !testFlag(MaximizeToFullScreen)) { + handleWindowStateChange(Qt::WindowNoState); ++ } + handleGeometryChange(); + break; + } +diff --git a/src/plugins/platforms/windows/qwindowswindow.h b/src/plugins/platforms/windows/qwindowswindow.h +index 6fffa1e6e9..cb1c9c1161 100644 +--- a/src/plugins/platforms/windows/qwindowswindow.h ++++ b/src/plugins/platforms/windows/qwindowswindow.h +@@ -265,6 +265,10 @@ private: + inline void setWindowState_sys(Qt::WindowState newState); + inline void setParent_sys(const QPlatformWindow *parent); + inline void updateTransientParent() const; ++ ++ // Patch: Fix possibility of add / remove taskbar icon of the window. ++ inline void clearTransientParent() const; ++ + void destroyWindow(); + inline bool isDropSiteEnabled() const { return m_dropTarget != 0; } + void setDropSiteEnabled(bool enabled); +diff --git a/src/plugins/platforms/xcb/qxcbnativeinterface.cpp b/src/plugins/platforms/xcb/qxcbnativeinterface.cpp +index 09e7ecf3a3..c0f15a4242 100644 +--- a/src/plugins/platforms/xcb/qxcbnativeinterface.cpp ++++ b/src/plugins/platforms/xcb/qxcbnativeinterface.cpp +@@ -79,7 +79,10 @@ static int resourceType(const QByteArray &key) + QByteArrayLiteral("rootwindow"), + QByteArrayLiteral("subpixeltype"), QByteArrayLiteral("antialiasingenabled"), + QByteArrayLiteral("nofonthinting"), +- QByteArrayLiteral("atspibus") ++ QByteArrayLiteral("atspibus"), ++ ++ // Patch: Backport compositing manager check from Qt 5.7 ++ QByteArrayLiteral("compositingenabled") + }; + const QByteArray *end = names + sizeof(names) / sizeof(names[0]); + const QByteArray *result = std::find(names, end, key); +@@ -252,6 +255,13 @@ void *QXcbNativeInterface::nativeResourceForScreen(const QByteArray &resourceStr + case RootWindow: + result = reinterpret_cast(xcbScreen->root()); + break; ++ ++ // Patch: Backport compositing manager check from Qt 5.7 ++ case CompositingEnabled: ++ if (QXcbVirtualDesktop *vd = xcbScreen->virtualDesktop()) ++ result = vd->compositingActive() ? this : Q_NULLPTR; ++ break; ++ + default: + break; + } +diff --git a/src/plugins/platforms/xcb/qxcbnativeinterface.h b/src/plugins/platforms/xcb/qxcbnativeinterface.h +index f88b710864..6f818a5a72 100644 +--- a/src/plugins/platforms/xcb/qxcbnativeinterface.h ++++ b/src/plugins/platforms/xcb/qxcbnativeinterface.h +@@ -68,7 +68,10 @@ public: + ScreenSubpixelType, + ScreenAntialiasingEnabled, + NoFontHinting, +- AtspiBus ++ AtspiBus, ++ ++ // Patch: Backport compositing manager check from Qt 5.7 ++ CompositingEnabled + }; + + QXcbNativeInterface(); +diff --git a/src/widgets/dialogs/qfiledialog.cpp b/src/widgets/dialogs/qfiledialog.cpp +index bc2de899f5..aa8f8df4ad 100644 +--- a/src/widgets/dialogs/qfiledialog.cpp ++++ b/src/widgets/dialogs/qfiledialog.cpp +@@ -1200,6 +1200,15 @@ QList QFileDialogPrivate::userSelectedFiles() const + return files; + } + ++// Patch: Adding select-by-url for Windows file dialog. ++QByteArray QFileDialogPrivate::userSelectedRemoteContent() const ++{ ++ if (nativeDialogInUse) ++ return selectedRemoteContent_sys(); ++ ++ return QByteArray(); ++} ++ + QStringList QFileDialogPrivate::addDefaultSuffixToFiles(const QStringList &filesToFix) const + { + QStringList files; +@@ -1267,6 +1276,14 @@ QStringList QFileDialog::selectedFiles() const + return files; + } + ++// Patch: Adding select-by-url for Windows file dialog. ++QByteArray QFileDialog::selectedRemoteContent() const ++{ ++ Q_D(const QFileDialog); ++ ++ return d->userSelectedRemoteContent(); ++} ++ + /*! + Returns a list of urls containing the selected files in the dialog. + If no files are selected, or the mode is not ExistingFiles or +diff --git a/src/widgets/dialogs/qfiledialog.h b/src/widgets/dialogs/qfiledialog.h +index ffe49a2dd2..42dc563c8a 100644 +--- a/src/widgets/dialogs/qfiledialog.h ++++ b/src/widgets/dialogs/qfiledialog.h +@@ -108,6 +108,9 @@ public: + void selectFile(const QString &filename); + QStringList selectedFiles() const; + ++ // Patch: Adding select-by-url for Windows file dialog. ++ QByteArray selectedRemoteContent() const; ++ + void selectUrl(const QUrl &url); + QList selectedUrls() const; + +diff --git a/src/widgets/dialogs/qfiledialog_p.h b/src/widgets/dialogs/qfiledialog_p.h +index f610e46f83..547a64695a 100644 +--- a/src/widgets/dialogs/qfiledialog_p.h ++++ b/src/widgets/dialogs/qfiledialog_p.h +@@ -123,6 +123,10 @@ public: + static QString initialSelection(const QUrl &path); + QStringList typedFiles() const; + QList userSelectedFiles() const; ++ ++ // Patch: Adding select-by-url for Windows file dialog. ++ QByteArray userSelectedRemoteContent() const; ++ + QStringList addDefaultSuffixToFiles(const QStringList &filesToFix) const; + QList addDefaultSuffixToUrls(const QList &urlsToFix) const; + bool removeDirectory(const QString &path); +@@ -256,6 +260,10 @@ public: + QUrl directory_sys() const; + void selectFile_sys(const QUrl &filename); + QList selectedFiles_sys() const; ++ ++ // Patch: Adding select-by-url for Windows file dialog. ++ QByteArray selectedRemoteContent_sys() const; ++ + void setFilter_sys(); + void selectNameFilter_sys(const QString &filter); + QString selectedNameFilter_sys() const; +@@ -393,6 +401,14 @@ inline QList QFileDialogPrivate::selectedFiles_sys() const + return QList(); + } + ++// Patch: Adding select-by-url for Windows file dialog. ++inline QByteArray QFileDialogPrivate::selectedRemoteContent_sys() const ++{ ++ if (QPlatformFileDialogHelper *helper = platformFileDialogHelper()) ++ return helper->selectedRemoteContent(); ++ return QByteArray(); ++} ++ + inline void QFileDialogPrivate::setFilter_sys() + { + if (QPlatformFileDialogHelper *helper = platformFileDialogHelper()) +diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp +index b1d80d7b8f..42e32fd404 100644 +--- a/src/widgets/kernel/qwidget.cpp ++++ b/src/widgets/kernel/qwidget.cpp +@@ -5138,6 +5138,17 @@ void QWidget::render(QPainter *painter, const QPoint &targetOffset, + return; // Fully transparent. + + Q_D(QWidget); ++ ++ // Patch: save and restore dirtyOpaqueChildren field. ++ // ++ // Just like in QWidget::grab() this field should be restored ++ // after the d->render() call, because it will be set to 1 and ++ // opaqueChildren field will be filled with empty region in ++ // case the widget is hidden (because all the opaque children ++ // will be skipped in isVisible() check). ++ // ++ const bool oldDirtyOpaqueChildren = d->dirtyOpaqueChildren; ++ + const bool inRenderWithPainter = d->extra && d->extra->inRenderWithPainter; + const QRegion toBePainted = !inRenderWithPainter ? d->prepareToRender(sourceRegion, renderFlags) + : sourceRegion; +@@ -5159,6 +5170,10 @@ void QWidget::render(QPainter *painter, const QPoint &targetOffset, + if (!inRenderWithPainter && (opacity < 1.0 || (target->devType() == QInternal::Printer))) { + d->render_helper(painter, targetOffset, toBePainted, renderFlags); + d->extra->inRenderWithPainter = inRenderWithPainter; ++ ++ // Patch: save and restore dirtyOpaqueChildren field. ++ d->dirtyOpaqueChildren = oldDirtyOpaqueChildren; ++ + return; + } + +@@ -5190,6 +5205,9 @@ void QWidget::render(QPainter *painter, const QPoint &targetOffset, + d->setSharedPainter(oldPainter); + + d->extra->inRenderWithPainter = inRenderWithPainter; ++ ++ // Patch: save and restore dirtyOpaqueChildren field. ++ d->dirtyOpaqueChildren = oldDirtyOpaqueChildren; + } + + static void sendResizeEvents(QWidget *target) +@@ -8769,7 +8787,8 @@ bool QWidget::event(QEvent *event) + case QEvent::KeyPress: { + QKeyEvent *k = (QKeyEvent *)event; + bool res = false; +- if (!(k->modifiers() & (Qt::ControlModifier | Qt::AltModifier))) { //### Add MetaModifier? ++ // Patch: Enable Ctrl+Tab and Ctrl+Shift+Tab / Ctrl+Backtab handle in-app. ++ if (!(k->modifiers() & (Qt::ControlModifier | Qt::AltModifier | Qt::MetaModifier))) { //### Add MetaModifier? + if (k->key() == Qt::Key_Backtab + || (k->key() == Qt::Key_Tab && (k->modifiers() & Qt::ShiftModifier))) + res = focusNextPrevChild(false); +diff --git a/src/widgets/util/qsystemtrayicon.cpp b/src/widgets/util/qsystemtrayicon.cpp +index 704142fe5c..7c4340e459 100644 +--- a/src/widgets/util/qsystemtrayicon.cpp ++++ b/src/widgets/util/qsystemtrayicon.cpp +@@ -709,6 +709,10 @@ void QSystemTrayIconPrivate::updateMenu_sys_qpa() + if (menu) { + addPlatformMenu(menu); + qpa_sys->updateMenu(menu->platformMenu()); ++ ++ // Patch: Create a rich os x tray icon (pixel-perfect, theme switching). ++ } else { ++ qpa_sys->updateMenu(nullptr); + } + } + +diff --git a/src/widgets/widgets/qabstractscrollarea.cpp b/src/widgets/widgets/qabstractscrollarea.cpp +index 2e2a042bf1..472e37722b 100644 +--- a/src/widgets/widgets/qabstractscrollarea.cpp ++++ b/src/widgets/widgets/qabstractscrollarea.cpp +@@ -640,15 +640,22 @@ scrolling range. + QSize QAbstractScrollArea::maximumViewportSize() const + { + Q_D(const QAbstractScrollArea); +- int hsbExt = d->hbar->sizeHint().height(); +- int vsbExt = d->vbar->sizeHint().width(); ++ // Patch: Count the sizeHint of the bar only if it is displayed. ++ //int hsbExt = d->hbar->sizeHint().height(); ++ //int vsbExt = d->vbar->sizeHint().width(); + + int f = 2 * d->frameWidth; + QSize max = size() - QSize(f + d->left + d->right, f + d->top + d->bottom); +- if (d->vbarpolicy == Qt::ScrollBarAlwaysOn) ++ ++ // Patch: Count the sizeHint of the bar only if it is displayed. ++ if (d->vbarpolicy == Qt::ScrollBarAlwaysOn) { ++ int vsbExt = d->vbar->sizeHint().width(); + max.rwidth() -= vsbExt; +- if (d->hbarpolicy == Qt::ScrollBarAlwaysOn) ++ } ++ if (d->hbarpolicy == Qt::ScrollBarAlwaysOn) { ++ int hsbExt = d->hbar->sizeHint().height(); + max.rheight() -= hsbExt; ++ } + return max; + } + +diff --git a/src/widgets/widgets/qwidgetlinecontrol.cpp b/src/widgets/widgets/qwidgetlinecontrol.cpp +index daf9f00c46..57499dc4a4 100644 +--- a/src/widgets/widgets/qwidgetlinecontrol.cpp ++++ b/src/widgets/widgets/qwidgetlinecontrol.cpp +@@ -40,6 +40,11 @@ + #include + #include + #include ++ ++// Patch: Enable Ctrl+key and Ctrl+Shift+key in all locales except German. ++// See https://github.com/telegramdesktop/tdesktop/pull/1185. ++#include ++ + #ifndef QT_NO_ACCESSIBILITY + #include "qaccessible.h" + #endif +@@ -1882,11 +1887,21 @@ void QWidgetLineControl::processKeyEvent(QKeyEvent* event) + } + + // QTBUG-35734: ignore Ctrl/Ctrl+Shift; accept only AltGr (Alt+Ctrl) on German keyboards +- if (unknown && !isReadOnly() +- && event->modifiers() != Qt::ControlModifier +- && event->modifiers() != (Qt::ControlModifier | Qt::ShiftModifier)) { ++ ++ // Patch: Enable Ctrl+key and Ctrl+Shift+key in all locales except German. ++ // See https://github.com/telegramdesktop/tdesktop/pull/1185. ++ bool skipCtrlAndCtrlShift = false; ++ if (QGuiApplication::inputMethod()->locale().language() == QLocale::German) { ++ if (event->modifiers() == Qt::ControlModifier ++ || event->modifiers() == (Qt::ControlModifier | Qt::ShiftModifier)) { ++ skipCtrlAndCtrlShift = true; ++ } ++ } ++ if (unknown && !isReadOnly() && !skipCtrlAndCtrlShift) { + QString t = event->text(); +- if (!t.isEmpty() && t.at(0).isPrint()) { ++ ++ // Patch: Enable ZWJ and ZWNJ characters to be in text input. ++ if (!t.isEmpty() && (t.at(0).isPrint() || t.at(0).unicode() == 0x200C || t.at(0).unicode() == 0x200D)) { + insert(t); + #ifndef QT_NO_COMPLETER + complete(event->key()); +diff --git a/src/widgets/widgets/qwidgettextcontrol.cpp b/src/widgets/widgets/qwidgettextcontrol.cpp +index deca002bf5..8a2023f503 100644 +--- a/src/widgets/widgets/qwidgettextcontrol.cpp ++++ b/src/widgets/widgets/qwidgettextcontrol.cpp +@@ -71,6 +71,11 @@ + #include + #include + #include ++ ++// Patch: Enable Ctrl+key and Ctrl+Shift+key in all locales except German. ++// See https://github.com/telegramdesktop/tdesktop/pull/1185. ++#include ++ + #include + #include + #include +@@ -1343,13 +1348,24 @@ void QWidgetTextControlPrivate::keyPressEvent(QKeyEvent *e) + process: + { + // QTBUG-35734: ignore Ctrl/Ctrl+Shift; accept only AltGr (Alt+Ctrl) on German keyboards +- if (e->modifiers() == Qt::ControlModifier +- || e->modifiers() == (Qt::ShiftModifier | Qt::ControlModifier)) { ++ ++ // Patch: Enable Ctrl+key and Ctrl+Shift+key in all locales except German. ++ // See https://github.com/telegramdesktop/tdesktop/pull/1185. ++ bool skipCtrlAndCtrlShift = false; ++ if (QGuiApplication::inputMethod()->locale().language() == QLocale::German) { ++ if (e->modifiers() == Qt::ControlModifier ++ || e->modifiers() == (Qt::ControlModifier | Qt::ShiftModifier)) { ++ skipCtrlAndCtrlShift = true; ++ } ++ } ++ if (skipCtrlAndCtrlShift) { + e->ignore(); + return; + } + QString text = e->text(); +- if (!text.isEmpty() && (text.at(0).isPrint() || text.at(0) == QLatin1Char('\t'))) { ++ ++ // Patch: Enable ZWJ and ZWNJ characters to be in text input. ++ if (!text.isEmpty() && (text.at(0).isPrint() || text.at(0) == QLatin1Char('\t') || text.at(0).unicode() == 0x200C || text.at(0).unicode() == 0x200D)) { + if (overwriteMode + // no need to call deleteChar() if we have a selection, insertText + // does it already