From 834bd67b2a3919fc212126073b6abbc62e6b47f0 Mon Sep 17 00:00:00 2001 From: ilya-fedin Date: Mon, 25 May 2020 01:58:35 +0400 Subject: [PATCH] Use upstream patches for appimage (#52) --- .github/workflows/appimage.yml | 25 +- Telegram/Patches/qtbase_5_12_8_appimage.diff | 1209 ------------------ Telegram/Patches/qtstyleplugins.diff | 87 -- Telegram/Patches/qtwayland_5_12_8.diff | 19 - docs/building-cmake.md | 2 +- 5 files changed, 16 insertions(+), 1326 deletions(-) delete mode 100644 Telegram/Patches/qtbase_5_12_8_appimage.diff delete mode 100644 Telegram/Patches/qtstyleplugins.diff delete mode 100644 Telegram/Patches/qtwayland_5_12_8.diff diff --git a/.github/workflows/appimage.yml b/.github/workflows/appimage.yml index f547dcd53..4048d5181 100644 --- a/.github/workflows/appimage.yml +++ b/.github/workflows/appimage.yml @@ -5,6 +5,7 @@ on: paths-ignore: - 'docs/**' - '**.md' + - '!docs/building-cmake.md' - 'changelog.txt' - 'kotatogram_changes.txt' - 'LEGAL' @@ -14,9 +15,6 @@ on: - 'snap/**' - 'Telegram/build/**' - 'Telegram/Patches/**' - - '!Telegram/Patches/qtbase_5_12_8_appimage.diff' - - '!Telegram/Patches/qtwayland_5_12_8.diff' - - '!Telegram/Patches/qtstyleplugins.diff' - 'Telegram/Resources/uwp/**' - 'Telegram/Resources/winrc/**' - 'Telegram/SourceFiles/platform/win/**' @@ -28,6 +26,7 @@ on: paths-ignore: - 'docs/**' - '**.md' + - '!docs/building-cmake.md' - 'changelog.txt' - 'kotatogram_changes.txt' - 'LEGAL' @@ -37,9 +36,6 @@ on: - 'snap/**' - 'Telegram/build/**' - 'Telegram/Patches/**' - - '!Telegram/Patches/qtbase_5_12_8_appimage.diff' - - '!Telegram/Patches/qtwayland_5_12_8.diff' - - '!Telegram/Patches/qtstyleplugins.diff' - 'Telegram/Resources/uwp/**' - 'Telegram/Resources/winrc/**' - 'Telegram/SourceFiles/platform/win/**' @@ -147,6 +143,15 @@ jobs: cd Libraries echo ::set-env name=LibrariesPath::`pwd` + - name: Patches. + run: | + echo "Find necessary commit from doc." + checkoutCommit=$(grep -A 1 "cd patches" $REPO_NAME/$DOC_PATH | sed -n 2p) + cd $LibrariesPath + git clone $GIT/desktop-app/patches.git + cd patches + eval $checkoutCommit + - name: OpenSSL cache. id: cache-openssl uses: actions/cache@v1 @@ -467,7 +472,7 @@ jobs: uses: actions/cache@v1 with: path: ${{ env.LibrariesPath }}/qt-cache - key: ${{ runner.OS }}-qt-${{ env.CACHE_KEY }}-${{ hashFiles('**/qtbase_5_12_8_appimage.diff') }}-${{ hashFiles('**/qtwayland_5_12_8.diff') }} + key: ${{ runner.OS }}-qt-${{ env.CACHE_KEY }}-${{ hashFiles('**/qtbase_5_12_8.diff') }}-${{ hashFiles('**/qtwayland_5_12_8.diff') }} - name: Qt 5.12.8 build. if: steps.cache-qt.outputs.cache-hit != 'true' run: | @@ -478,10 +483,10 @@ jobs: perl init-repository --module-subset=qtbase,qtwayland,qtimageformats,qtsvg,qttools,qtx11extras git submodule update qtbase qtwayland qtimageformats qtsvg qttools qtx11extras cd qtbase - git apply ../../../$REPO_NAME/Telegram/Patches/qtbase_${QT}_appimage.diff + git apply ../../patches/qtbase_${QT}.diff cd .. cd qtwayland - git apply ../../../$REPO_NAME/Telegram/Patches/qtwayland_${QT}.diff + git apply ../../patches/qtwayland_${QT}.diff cd .. ./configure -prefix /usr/local \ @@ -517,7 +522,7 @@ jobs: git clone --depth=1 git://code.qt.io/qt/qtstyleplugins.git cd qtstyleplugins - git apply ../../$REPO_NAME/Telegram/Patches/qtstyleplugins.diff + git apply ../patches/qtstyleplugins.diff qmake make -j$(nproc) sudo make install diff --git a/Telegram/Patches/qtbase_5_12_8_appimage.diff b/Telegram/Patches/qtbase_5_12_8_appimage.diff deleted file mode 100644 index b6786792e..000000000 --- a/Telegram/Patches/qtbase_5_12_8_appimage.diff +++ /dev/null @@ -1,1209 +0,0 @@ -diff --git a/src/corelib/kernel/qcore_mac_objc.mm b/src/corelib/kernel/qcore_mac_objc.mm -index 266faca0ed..cf9dafb6d8 100644 ---- a/src/corelib/kernel/qcore_mac_objc.mm -+++ b/src/corelib/kernel/qcore_mac_objc.mm -@@ -140,7 +140,8 @@ QMacAutoReleasePool::QMacAutoReleasePool() - { - Class trackerClass = [QMacAutoReleasePoolTracker class]; - --#ifdef QT_DEBUG -+// Patch: Disable this debug code because it is very slow. -+#ifdef QT_DEBUG____REMOVED - void *poolFrame = nullptr; - if (__builtin_available(macOS 10.14, iOS 12.0, tvOS 12.0, watchOS 5.0, *)) { - void *frame; -diff --git a/src/gui/kernel/qstylehints.cpp b/src/gui/kernel/qstylehints.cpp -index 48060a2c37..fff3271ec9 100644 ---- a/src/gui/kernel/qstylehints.cpp -+++ b/src/gui/kernel/qstylehints.cpp -@@ -374,7 +374,11 @@ bool QStyleHints::showIsMaximized() const - */ - bool QStyleHints::showShortcutsInContextMenus() const - { -- return themeableHint(QPlatformTheme::ShowShortcutsInContextMenus, QPlatformIntegration::ShowShortcutsInContextMenus).toBool(); -+ // Patch: Always show hotkeys in the standard context menu. -+ // This patch can be removed in 5.13 and later versions. -+ // See: https://bugreports.qt.io/browse/QTBUG-71471 -+ return true; -+ // return themeableHint(QPlatformTheme::ShowShortcutsInContextMenus, QPlatformIntegration::ShowShortcutsInContextMenus).toBool(); - } - - /*! -diff --git a/src/gui/painting/qbezier.cpp b/src/gui/painting/qbezier.cpp -index 65e6063fe4..fcf19a1a63 100644 ---- a/src/gui/painting/qbezier.cpp -+++ b/src/gui/painting/qbezier.cpp -@@ -400,6 +400,33 @@ static bool addCircle(const QBezier *b, qreal offset, QBezier *o) - return true; - } - -+// 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; -+} -+#endif // Q_OS_WIN -+ - int QBezier::shifted(QBezier *curveSegments, int maxSegments, qreal offset, float threshold) const - { - Q_ASSERT(curveSegments); -diff --git a/src/gui/painting/qbezier_p.h b/src/gui/painting/qbezier_p.h -index f8a91e9ef3..50c60b2d71 100644 ---- a/src/gui/painting/qbezier_p.h -+++ b/src/gui/painting/qbezier_p.h -@@ -222,6 +222,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); -@@ -245,6 +247,7 @@ inline void QBezier::split(QBezier *firstHalf, QBezier *secondHalf) const - secondHalf->y2 = (secondHalf->y3 + c)*.5; - firstHalf->y4 = secondHalf->y1 = (firstHalf->y3 + secondHalf->y2)*.5; - } -+#endif // Q_OS_WIN - - inline void QBezier::parameterSplitLeft(qreal t, QBezier *left) - { -diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp -index b70b29e54e..9519894076 100644 ---- a/src/gui/painting/qpainter.cpp -+++ b/src/gui/painting/qpainter.cpp -@@ -6245,6 +6245,91 @@ static QPixmap generateWavyPixmap(qreal maxRadius, const QPen &pen) - return pixmap; - } - -+// Patch: Improved underline with SpellCheck style for macOS and Windows. -+// Added implementation of underline drawing from Chrome. -+static QPixmap generateChromeSpellcheckPixmap(qreal descent, qreal factor, const QPen &pen) { -+ QString key = QLatin1String("ChromeUnderline-") -+ % pen.color().name() -+ % HexString(factor) -+ % HexString(pen.widthF()); -+ -+ QPixmap pixmap; -+ if (QPixmapCache::find(key, pixmap)) { -+ return pixmap; -+ } -+ // https://chromium.googlesource.com/chromium/src/+/refs/heads/master/third_party/blink/renderer/core/paint/document_marker_painter.cc -+ -+#ifdef Q_OS_MAC -+ -+ constexpr qreal kMarkerHeight = 3; -+ -+ const qreal height = kMarkerHeight * factor; -+ const qreal width = height * 2; -+ -+ pixmap = QPixmap(qCeil(width), qFloor(height) * 2); -+ pixmap.setDevicePixelRatio(qApp->devicePixelRatio()); -+ pixmap.fill(Qt::transparent); -+ { -+ QPainter imgPainter(&pixmap); -+ imgPainter.setPen(Qt::NoPen); -+ imgPainter.setBrush(pen.color()); -+ imgPainter.setRenderHints( -+ QPainter::Antialiasing | QPainter::SmoothPixmapTransform); -+ imgPainter.drawEllipse(0, 0, qFloor(height), qFloor(height)); -+ } -+ -+#else -+ -+ constexpr qreal kMarkerWidth = 4; -+ constexpr qreal kMarkerHeight = 2; -+ -+ const auto x1 = (kMarkerWidth * -3 / 8) * factor; -+ const auto y1 = (kMarkerHeight * 3 / 4) * factor; -+ -+ const auto cY = (kMarkerHeight * 1 / 4) * factor; -+ -+ const auto c1X1 = (kMarkerWidth * -1 / 8) * factor; -+ const auto c1X2 = (kMarkerWidth * 3 / 8) * factor; -+ const auto c1X3 = (kMarkerWidth * 7 / 8) * factor; -+ -+ const auto c2X1 = (kMarkerWidth * 1 / 8) * factor; -+ const auto c2X2 = (kMarkerWidth * 5 / 8) * factor; -+ const auto c2X3 = (kMarkerWidth * 9 / 8) * factor; -+ -+ QPainterPath path; -+ path.moveTo(x1, y1); -+ path.cubicTo(c1X1, y1, -+ c1X1, cY, -+ c2X1, cY); -+ path.cubicTo(c1X2, cY, -+ c1X2, y1, -+ c2X2, y1); -+ path.cubicTo(c1X3, y1, -+ c1X3, cY, -+ c2X3, cY); -+ -+ pixmap = QPixmap(kMarkerWidth * factor, kMarkerHeight * factor * 2); -+ pixmap.fill(Qt::transparent); -+ { -+ QPen wavePen = pen; -+ wavePen.setCapStyle(Qt::RoundCap); -+ wavePen.setJoinStyle(Qt::RoundJoin); -+ wavePen.setWidthF(1 * factor); -+ -+ QPainter imgPainter(&pixmap); -+ imgPainter.setPen(std::move(wavePen)); -+ imgPainter.setRenderHint(QPainter::Antialiasing); -+ imgPainter.translate(0, descent - (kMarkerHeight * factor)); -+ imgPainter.drawPath(std::move(path)); -+ } -+ -+#endif -+ -+ QPixmapCache::insert(std::move(key), pixmap); -+ -+ return pixmap; -+} -+ - static void drawTextItemDecoration(QPainter *painter, const QPointF &pos, const QFontEngine *fe, QTextEngine *textEngine, - QTextCharFormat::UnderlineStyle underlineStyle, - QTextItem::RenderFlags flags, qreal width, -@@ -6262,7 +6347,9 @@ static void drawTextItemDecoration(QPainter *painter, const QPointF &pos, const - pen.setWidthF(fe->lineThickness().toReal()); - pen.setCapStyle(Qt::FlatCap); - -- QLineF line(qFloor(pos.x()), pos.y(), qFloor(pos.x() + width), pos.y()); -+ // Patch: Improved underline with SpellCheck style for macOS and Windows. -+ // Slightly move the beginning of the underline to the right. -+ QLineF line(qFloor(pos.x() + 1), pos.y(), qFloor(pos.x() + width), pos.y()); - - bool wasCompatiblePainting = painter->renderHints() - & QPainter::Qt4CompatiblePainting; -@@ -6273,13 +6360,29 @@ static void drawTextItemDecoration(QPainter *painter, const QPointF &pos, const - const qreal underlineOffset = fe->underlinePosition().toReal(); - - if (underlineStyle == QTextCharFormat::SpellCheckUnderline) { -- QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme(); -- if (theme) -- underlineStyle = QTextCharFormat::UnderlineStyle(theme->themeHint(QPlatformTheme::SpellCheckUnderlineStyle).toInt()); -- if (underlineStyle == QTextCharFormat::SpellCheckUnderline) // still not resolved -- underlineStyle = QTextCharFormat::WaveUnderline; -- } -+ const qreal fontFactor = qreal(charFormat.font().pixelSize()) / qreal(10.); -+ painter->save(); -+ painter->translate(0, pos.y() + 1); -+ const qreal maxHeight = fe->descent().toReal() - qreal(1); -+ -+ QColor uc = charFormat.underlineColor(); -+ if (uc.isValid()) -+ pen.setColor(uc); - -+ const QPixmap wave = generateChromeSpellcheckPixmap(maxHeight, fontFactor, pen); -+ const int descent = qFloor(maxHeight); -+ -+ painter->setBrushOrigin(painter->brushOrigin().x(), 0); -+#ifdef Q_OS_MAC -+ const auto h = wave.height() / 2; -+ painter->drawTiledPixmap( -+ QRectF(pos.x(), (descent - h) / 2., qCeil(width), h), -+ wave); -+#else -+ painter->fillRect(pos.x(), 0, qCeil(width), descent, wave); -+#endif -+ painter->restore(); -+ } else - if (underlineStyle == QTextCharFormat::WaveUnderline) { - painter->save(); - painter->translate(0, pos.y() + 1); -diff --git a/src/gui/text/qinputcontrol.cpp b/src/gui/text/qinputcontrol.cpp -index 3381fdb673..6036f052e9 100644 ---- a/src/gui/text/qinputcontrol.cpp -+++ b/src/gui/text/qinputcontrol.cpp -@@ -40,6 +40,10 @@ - #include "qinputcontrol_p.h" - #include - -+// Patch: Enable Ctrl+key and Ctrl+Shift+key in all locales except German. -+// See https://github.com/telegramdesktop/tdesktop/pull/1185. -+#include -+ - QT_BEGIN_NAMESPACE - - QInputControl::QInputControl(Type type, QObject *parent) -@@ -67,9 +71,16 @@ bool QInputControl::isAcceptableInput(const QKeyEvent *event) const - if (c.category() == QChar::Other_Format) - return true; - -- // QTBUG-35734: ignore Ctrl/Ctrl+Shift; accept only AltGr (Alt+Ctrl) on German keyboards -- if (event->modifiers() == Qt::ControlModifier -- || event->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 (event->modifiers() == Qt::ControlModifier -+ || event->modifiers() == (Qt::ControlModifier | Qt::ShiftModifier)) { -+ skipCtrlAndCtrlShift = true; -+ } -+ } -+ if (skipCtrlAndCtrlShift) { - return false; - } - -diff --git a/src/gui/text/qtextcursor.cpp b/src/gui/text/qtextcursor.cpp -index c88497840f..2b08d13834 100644 ---- a/src/gui/text/qtextcursor.cpp -+++ b/src/gui/text/qtextcursor.cpp -@@ -510,14 +510,16 @@ bool QTextCursorPrivate::movePosition(QTextCursor::MoveOperation op, QTextCursor - const int len = blockIt.length() - 1; - if (relativePos >= len) - return false; -- if (engine->atWordSeparator(relativePos)) { -- ++relativePos; -- while (relativePos < len && engine->atWordSeparator(relativePos)) -- ++relativePos; -- } else { -- while (relativePos < len && !attributes[relativePos].whiteSpace && !engine->atWordSeparator(relativePos)) -- ++relativePos; -- } -+ // Patch: Improved apostrophe processing. -+ relativePos = engine->toEdge(relativePos, len, true); -+ // if (engine->atWordSeparator(relativePos)) { -+ // ++relativePos; -+ // while (relativePos < len && engine->atWordSeparator(relativePos)) -+ // ++relativePos; -+ // } else { -+ // while (relativePos < len && !attributes[relativePos].whiteSpace && !engine->atWordSeparator(relativePos)) -+ // ++relativePos; -+ // } - newPosition = blockIt.position() + relativePos; - break; - } -diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp -index a7834587b1..cabe897268 100644 ---- a/src/gui/text/qtextengine.cpp -+++ b/src/gui/text/qtextengine.cpp -@@ -3028,7 +3028,8 @@ bool QTextEngine::atWordSeparator(int position) const - case '&': - case '^': - case '*': -- case '\'': -+ // Patch: Make the apostrophe a non-separator for words. -+ //case '\'': - case '"': - case '`': - case '~': -@@ -3041,6 +3042,74 @@ bool QTextEngine::atWordSeparator(int position) const - return false; - } - -+// Patch: Improved apostrophe processing. -+// We should consider apostrophes as word separators when there is more than -+// one apostrophe in a row, or when the apostrophe is at the beginning or end -+// of the word. -+int QTextEngine::toEdge(int pos, int len, bool isRightDirection) { -+ const auto step = isRightDirection ? 1 : -1; -+ const auto next = isRightDirection ? 0 : -1; -+ -+ QCharAttributes *attributes = const_cast(this->attributes()); -+ -+ const auto atApostrophe = [&](int position) { -+ return layoutData->string.at(position).unicode() == '\''; -+ }; -+ -+ const auto atSepOrApost = [&](int position) { -+ return atApostrophe(position) || atWordSeparator(position); -+ }; -+ -+ const auto inBounds = [&](int position) { -+ return isRightDirection -+ ? position < len -+ : position > 0; -+ }; -+ -+ const auto atSepOrSpace = [&](int position) { -+ return attributes[position].whiteSpace || atWordSeparator(position); -+ }; -+ -+ const auto isApostropheInWord = [&](int position) { -+ if (!atApostrophe(position)) { -+ return false; -+ } -+ auto p = position - 1; -+ if (p <= 0 || atSepOrSpace(p)) { -+ return false; -+ } -+ p = position + 1; -+ if (p >= len || atSepOrSpace(p)) { -+ return false; -+ } -+ return true; -+ }; -+ -+ auto counter = 0; -+ while (inBounds(pos) && atSepOrApost(pos + next)) { -+ counter++; -+ pos += step; -+ } -+ // If it's not the single apostrophe, then that's non-letter part of text. -+ if (counter > 1 || (counter == 1 && !isApostropheInWord(pos - step + next))) { -+ return pos; -+ } -+ -+ bool isPrevApostrophe = false; -+ while (inBounds(pos) && !atSepOrSpace(pos + next)) { -+ bool isNextApostrophe = atApostrophe(pos + next); -+ if (isPrevApostrophe && isNextApostrophe) { -+ break; -+ } -+ pos += step; -+ isPrevApostrophe = isNextApostrophe; -+ } -+ if (isPrevApostrophe) { -+ pos += -step; -+ } -+ return pos; -+} -+ - void QTextEngine::setPreeditArea(int position, const QString &preeditText) - { - if (preeditText.isEmpty()) { -diff --git a/src/gui/text/qtextengine_p.h b/src/gui/text/qtextengine_p.h -index e9187ea605..51997ba066 100644 ---- a/src/gui/text/qtextengine_p.h -+++ b/src/gui/text/qtextengine_p.h -@@ -622,6 +622,8 @@ private: - - public: - bool atWordSeparator(int position) const; -+ // Patch: Improved apostrophe processing. -+ int toEdge(int pos, int len, bool isRightDirection); - - QString elidedText(Qt::TextElideMode mode, const QFixed &width, int flags = 0, int from = 0, int count = -1) const; - -diff --git a/src/gui/text/qtextlayout.cpp b/src/gui/text/qtextlayout.cpp -index f3f0caa379..081c5f03c0 100644 ---- a/src/gui/text/qtextlayout.cpp -+++ b/src/gui/text/qtextlayout.cpp -@@ -706,16 +706,22 @@ int QTextLayout::nextCursorPosition(int oldPos, CursorMode mode) const - while (oldPos < len && !attributes[oldPos].graphemeBoundary) - oldPos++; - } else { -- if (oldPos < len && d->atWordSeparator(oldPos)) { -- oldPos++; -- while (oldPos < len && d->atWordSeparator(oldPos)) -- oldPos++; -- } else { -- while (oldPos < len && !attributes[oldPos].whiteSpace && !d->atWordSeparator(oldPos)) -- 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++; -+ // Patch: Improved apostrophe processing. -+ oldPos = d->toEdge(oldPos, len, true); -+ // if (oldPos < len && d->atWordSeparator(oldPos)) { -+ // oldPos++; -+ // while (oldPos < len && d->atWordSeparator(oldPos)) -+ // oldPos++; -+ // } else { -+ // while (oldPos < len && !attributes[oldPos].whiteSpace && !d->atWordSeparator(oldPos)) -+ // 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; -@@ -745,14 +751,16 @@ int QTextLayout::previousCursorPosition(int oldPos, CursorMode mode) const - while (oldPos > 0 && attributes[oldPos - 1].whiteSpace) - oldPos--; - -- if (oldPos && d->atWordSeparator(oldPos-1)) { -- oldPos--; -- while (oldPos && d->atWordSeparator(oldPos-1)) -- oldPos--; -- } else { -- while (oldPos > 0 && !attributes[oldPos - 1].whiteSpace && !d->atWordSeparator(oldPos-1)) -- oldPos--; -- } -+ // Patch: Improved apostrophe processing. -+ oldPos = d->toEdge(oldPos, len, false); -+ // if (oldPos && d->atWordSeparator(oldPos-1)) { -+ // oldPos--; -+ // while (oldPos && d->atWordSeparator(oldPos-1)) -+ // oldPos--; -+ // } else { -+ // while (oldPos > 0 && !attributes[oldPos - 1].whiteSpace && !d->atWordSeparator(oldPos-1)) -+ // oldPos--; -+ // } - } - - return oldPos; -diff --git a/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase.cpp b/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase.cpp -index 9e6e5d88c7..dc5986d9c7 100644 ---- a/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase.cpp -+++ b/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase.cpp -@@ -1694,50 +1694,50 @@ HFONT QWindowsFontDatabase::systemFont() - - static const char *other_tryFonts[] = { - "Arial", -- "MS UI Gothic", -- "Gulim", -- "SimSun", -- "PMingLiU", -+ "Yu Gothic UI", -+ "Malgun Gothic", -+ "Microsoft YaHei UI", -+ "Microsoft JhengHei UI", - "Arial Unicode MS", - 0 - }; - - static const char *jp_tryFonts [] = { -- "MS UI Gothic", -+ "Yu Gothic UI", - "Arial", -- "Gulim", -- "SimSun", -- "PMingLiU", -+ "Malgun Gothic", -+ "Microsoft YaHei UI", -+ "Microsoft JhengHei UI", - "Arial Unicode MS", - 0 - }; - - static const char *ch_CN_tryFonts [] = { -- "SimSun", -+ "Microsoft YaHei UI", - "Arial", -- "PMingLiU", -- "Gulim", -- "MS UI Gothic", -+ "Microsoft JhengHei UI", -+ "Malgun Gothic", -+ "Yu Gothic UI", - "Arial Unicode MS", - 0 - }; - - static const char *ch_TW_tryFonts [] = { -- "PMingLiU", -+ "Microsoft JhengHei UI", - "Arial", -- "SimSun", -- "Gulim", -- "MS UI Gothic", -+ "Microsoft YaHei UI", -+ "Malgun Gothic", -+ "Yu Gothic UI", - "Arial Unicode MS", - 0 - }; - - static const char *kr_tryFonts[] = { -- "Gulim", -+ "Malgun Gothic", - "Arial", -- "PMingLiU", -- "SimSun", -- "MS UI Gothic", -+ "Microsoft JhengHei UI", -+ "Microsoft YaHei UI", -+ "Yu Gothic UI", - "Arial Unicode MS", - 0 - }; -diff --git a/src/platformsupport/linuxaccessibility/constant_mappings.cpp b/src/platformsupport/linuxaccessibility/constant_mappings.cpp -index fce2919e73..4a7d0f7d92 100644 ---- a/src/platformsupport/linuxaccessibility/constant_mappings.cpp -+++ b/src/platformsupport/linuxaccessibility/constant_mappings.cpp -@@ -79,7 +79,12 @@ quint64 spiStatesFromQState(QAccessible::State state) - if (state.checkStateMixed) - setSpiStateBit(&spiState, ATSPI_STATE_INDETERMINATE); - if (state.readOnly) -+// Patch: Support build with AT-SPI version below 2.16. -+#ifdef ATSPI_STATE_READ_ONLY - setSpiStateBit(&spiState, ATSPI_STATE_READ_ONLY); -+#else // ATSPI_STATE_READ_ONLY -+ unsetSpiStateBit(&spiState, ATSPI_STATE_EDITABLE); -+#endif // ATSPI_STATE_READ_ONLY - // if (state.HotTracked) - if (state.defaultButton) - setSpiStateBit(&spiState, ATSPI_STATE_IS_DEFAULT); -diff --git a/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontext.cpp b/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontext.cpp -index 81a730232c..42bab9aa4b 100644 ---- a/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontext.cpp -+++ b/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontext.cpp -@@ -273,6 +273,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/platforms/cocoa/qcocoaapplicationdelegate.mm b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm -index 2cf6672da9..ef25bb4541 100644 ---- a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm -+++ b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm -@@ -175,7 +175,8 @@ QT_USE_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]) { -@@ -252,7 +253,11 @@ QT_USE_NAMESPACE - - - (void)applicationDidFinishLaunching:(NSNotification *)aNotification - { -- Q_UNUSED(aNotification); -+ // Patch: We need to catch that notification in delegate. -+ if (reflectionDelegate -+ && [reflectionDelegate respondsToSelector:@selector(applicationDidFinishLaunching:)]) -+ [reflectionDelegate applicationDidFinishLaunching:aNotification]; -+ - inLaunch = false; - - if (qEnvironmentVariableIsEmpty("QT_MAC_DISABLE_FOREGROUND_APPLICATION_TRANSFORM")) { -diff --git a/src/plugins/platforms/cocoa/qcocoakeymapper.mm b/src/plugins/platforms/cocoa/qcocoakeymapper.mm -index 350ae4b9be..457bb3408d 100644 ---- a/src/plugins/platforms/cocoa/qcocoakeymapper.mm -+++ b/src/plugins/platforms/cocoa/qcocoakeymapper.mm -@@ -462,7 +462,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 non-english layout 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 597cfa8318..579d79734d 100644 ---- a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm -+++ b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm -@@ -96,12 +96,17 @@ QT_USE_NAMESPACE - - @interface QT_MANGLE_NAMESPACE(QNSStatusItem) : NSObject - @property (nonatomic, assign) QCocoaMenu *menu; -+// Patch: Create a rich os x tray icon (pixel-perfect, theme switching). -+@property (nonatomic, assign) bool menuVisible; -+@property (nonatomic, readonly) bool iconSelected; - @property (nonatomic, assign) QIcon icon; - @property (nonatomic, readonly) NSStatusItem *item; - @property (nonatomic, readonly) QRectF geometry; - - (instancetype)initWithSysTray:(QCocoaSystemTrayIcon *)systray; - - (void)triggerSelector:(id)sender button:(Qt::MouseButton)mouseButton; - - (void)doubleClickSelector:(id)sender; -+- (void)setIconSelected:(bool)selected; -+- (bool)hasMenu; - @end - - @interface QT_MANGLE_NAMESPACE(QNSImageView) : NSImageView -@@ -173,7 +178,10 @@ 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; - -@@ -183,8 +191,12 @@ 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 -@@ -200,9 +212,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. -@@ -301,6 +313,10 @@ QT_END_NAMESPACE - { - self.down = NO; - -+ // Patch: Create a rich os x tray icon (pixel-perfect, theme switching). -+ [self.parent setIconSelected:false]; -+ self.parent.menuVisible = false; -+ - [self setNeedsDisplay:YES]; - } - -@@ -310,6 +326,9 @@ QT_END_NAMESPACE - int clickCount = [mouseEvent clickCount]; - [self setNeedsDisplay:YES]; - -+ // Patch: Create a rich os x tray icon (pixel-perfect, theme switching). -+ [self.parent setIconSelected:((clickCount != 2) && [self.parent hasMenu])]; -+ - if (clickCount == 2) { - [self menuTrackingDone:nil]; - [self.parent doubleClickSelector:self]; -@@ -326,6 +345,10 @@ QT_END_NAMESPACE - - (void)mouseUp:(NSEvent *)mouseEvent - { - Q_UNUSED(mouseEvent); -+ -+ // Patch: Create a rich os x tray icon (pixel-perfect, theme switching). -+ [self.parent setIconSelected:false]; -+ - [self menuTrackingDone:nil]; - } - -@@ -337,6 +360,10 @@ QT_END_NAMESPACE - - (void)rightMouseUp:(NSEvent *)mouseEvent - { - Q_UNUSED(mouseEvent); -+ -+ // Patch: Create a rich os x tray icon (pixel-perfect, theme switching). -+ [self.parent setIconSelected:false]; -+ - [self menuTrackingDone:nil]; - } - -@@ -352,7 +379,8 @@ QT_END_NAMESPACE - } - - - (void)drawRect:(NSRect)rect { -- [[self.parent item] drawStatusBarBackgroundInRect:rect withHighlight:self.down]; -+ // Patch: Create a rich os x tray icon (pixel-perfect, theme switching). -+ [[self.parent item] drawStatusBarBackgroundInRect:rect withHighlight:([self.parent hasMenu] && self.down)]; - [super drawRect:rect]; - } - @end -@@ -372,6 +400,10 @@ QT_END_NAMESPACE - if (self) { - item = [[[NSStatusBar systemStatusBar] statusItemWithLength:NSSquareStatusItemLength] retain]; - menu = nullptr; -+ -+ // Patch: Create a rich os x tray icon (pixel-perfect, theme switching). -+ self.menuVisible = false; -+ - systray = sys; - imageCell = [[QNSImageView alloc] initWithParent:self]; - [item setView: imageCell]; -@@ -382,6 +414,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.parent = nil; - [imageCell release]; - [item release]; -@@ -416,6 +453,10 @@ QT_END_NAMESPACE - selector:@selector(menuTrackingDone:) - name:NSMenuDidEndTrackingNotification - object:m]; -+ -+ // Patch: Create a rich os x tray icon (pixel-perfect, theme switching). -+ self.menuVisible = true; -+ - [item popUpStatusItemMenu: m]; - } - } -@@ -427,6 +468,15 @@ QT_END_NAMESPACE - emit systray->activated(QPlatformSystemTrayIcon::DoubleClick); - } - -+- (void)setIconSelected:(bool)selected { -+ _iconSelected = selected; -+ systray->updateIcon(icon); -+} -+ -+- (bool)hasMenu { -+ return menu != nil; -+} -+ - - (BOOL)userNotificationCenter:(NSUserNotificationCenter *)center shouldPresentNotification:(NSUserNotification *)notification { - Q_UNUSED(center); - Q_UNUSED(notification); -diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm -index 3008a056a2..d98eade4a3 100644 ---- a/src/plugins/platforms/cocoa/qcocoawindow.mm -+++ b/src/plugins/platforms/cocoa/qcocoawindow.mm -@@ -499,6 +499,15 @@ NSUInteger QCocoaWindow::windowStyleMask(Qt::WindowFlags flags) - // Select base window type. Note that the value of NSBorderlessWindowMask is 0. - NSUInteger styleMask = (frameless || !resizable) ? NSWindowStyleMaskBorderless : NSWindowStyleMaskResizable; - -+ // Patch: allow creating panels floating on all spaces in macOS. -+ // If you call "setCollectionBehavior:NSWindowCollectionBehaviorFullScreenAuxiliary" before -+ // setting the "NSWindowStyleMaskNonactivatingPanel" 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 |= NSWindowStyleMaskNonactivatingPanel; -+ } -+ - if (frameless) { - // No further customizations for frameless since there are no window decorations. - } else if (flags & Qt::CustomizeWindowHint) { -diff --git a/src/plugins/platforms/cocoa/qnsview_keys.mm b/src/plugins/platforms/cocoa/qnsview_keys.mm -index ad751279bb..9a9d19693e 100644 ---- a/src/plugins/platforms/cocoa/qnsview_keys.mm -+++ b/src/plugins/platforms/cocoa/qnsview_keys.mm -@@ -86,21 +86,29 @@ - quint32 nativeVirtualKey = [nsevent keyCode]; - - QChar ch = QChar::ReplacementCharacter; -- int keyCode = Qt::Key_unknown; -- -- // If a dead key occurs as a result of pressing a key combination then -- // characters will have 0 length, but charactersIgnoringModifiers will -- // have a valid character in it. This enables key combinations such as -- // ALT+E to be used as a shortcut with an English keyboard even though -- // pressing ALT+E will give a dead key while doing normal text input. -- if ([characters length] != 0 || [charactersIgnoringModifiers length] != 0) { -- auto ctrlOrMetaModifier = qApp->testAttribute(Qt::AA_MacDontSwapCtrlAndMeta) ? Qt::ControlModifier : Qt::MetaModifier; -- if (((modifiers & ctrlOrMetaModifier) || (modifiers & Qt::AltModifier)) && ([charactersIgnoringModifiers length] != 0)) -- ch = QChar([charactersIgnoringModifiers characterAtIndex:0]); -- else if ([characters length] != 0) -- 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]; -+ // int keyCode = Qt::Key_unknown; -+ -+ // // If a dead key occurs as a result of pressing a key combination then -+ // // characters will have 0 length, but charactersIgnoringModifiers will -+ // // have a valid character in it. This enables key combinations such as -+ // // ALT+E to be used as a shortcut with an English keyboard even though -+ // // pressing ALT+E will give a dead key while doing normal text input. -+ // if ([characters length] != 0 || [charactersIgnoringModifiers length] != 0) { -+ // auto ctrlOrMetaModifier = qApp->testAttribute(Qt::AA_MacDontSwapCtrlAndMeta) ? Qt::ControlModifier : Qt::MetaModifier; -+ // if (((modifiers & ctrlOrMetaModifier) || (modifiers & Qt::AltModifier)) && ([charactersIgnoringModifiers length] != 0)) -+ // ch = QChar([charactersIgnoringModifiers characterAtIndex:0]); -+ // else if ([characters length] != 0) -+ // ch = QChar([characters characterAtIndex:0]); -+ // keyCode = [self convertKeyCode:ch]; -+ // } - - // we will send a key event unless the input method sets m_sendKeyEvent to false - m_sendKeyEvent = true; -@@ -196,6 +204,23 @@ - [super keyUp:nsevent]; - } - -+// 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); -diff --git a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp -index 9de3268fc8..8b281c95db 100644 ---- a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp -+++ b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp -@@ -1179,7 +1179,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 -@@ -1456,7 +1463,8 @@ static QString createTemporaryItemCopy(QWindowsShellItem &qItem, QString *errorM - static QUrl itemToDialogUrl(QWindowsShellItem &qItem, QString *errorMessage) - { - QUrl url = qItem.url(); -- if (url.isLocalFile() || url.scheme().startsWith(QLatin1String("http"))) -+ // Patch: Make loaded 'http' resources copy. -+ if (url.isLocalFile()/*|| url.scheme().startsWith(QLatin1String("http"))*/) - return url; - const QString path = qItem.path(); - if (path.isEmpty() && !qItem.isDir() && qItem.canStream()) { -diff --git a/src/plugins/platforms/windows/qwindowsservices.cpp b/src/plugins/platforms/windows/qwindowsservices.cpp -index 9504513a5e..811f3d62bd 100644 ---- a/src/plugins/platforms/windows/qwindowsservices.cpp -+++ b/src/plugins/platforms/windows/qwindowsservices.cpp -@@ -125,6 +125,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(QLatin1String("%1"), url.toString(QUrl::FullyEncoded)); -diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp -index 7d511bf0d7..da3879cb56 100644 ---- a/src/plugins/platforms/windows/qwindowswindow.cpp -+++ b/src/plugins/platforms/windows/qwindowswindow.cpp -@@ -1351,7 +1351,8 @@ void QWindowsWindow::destroyWindow() - for (QWindow *w : tlw) { - if (w->transientParent() == window()) { - if (QWindowsWindow *tw = QWindowsWindow::windowsWindowOf(w)) -- tw->updateTransientParent(); -+ // Patch: Fix possibility of add / remove taskbar icon of the window. -+ tw->clearTransientParent(); - } - } - QWindowsContext *context = QWindowsContext::instance(); -@@ -1579,6 +1580,19 @@ void QWindowsWindow::updateTransientParent() const - // window is found, which can cause issues with modality. Loop up to top level. - while (newTransientParent && (GetWindowLongPtr(newTransientParent, GWL_STYLE) & WS_CHILD) != 0) - newTransientParent = GetParent(newTransientParent); -+ // Patch: Fix possibility of add / remove taskbar icon of the window. -+ if (newTransientParent && newTransientParent != oldTransientParent) -+ SetWindowLongPtr(m_data.hwnd, GWL_HWNDPARENT, (LONG_PTR)newTransientParent); -+} -+ -+// Patch: Fix possibility of add / remove taskbar icon of the window. -+void QWindowsWindow::clearTransientParent() const -+{ -+ 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 = GetWindow(m_data.hwnd, GW_OWNER); -+ HWND newTransientParent = 0; - - if (newTransientParent != oldTransientParent) - SetWindowLongPtr(m_data.hwnd, GWL_HWNDPARENT, LONG_PTR(newTransientParent)); -diff --git a/src/plugins/platforms/windows/qwindowswindow.h b/src/plugins/platforms/windows/qwindowswindow.h -index ce67e46df3..a60edc151f 100644 ---- a/src/plugins/platforms/windows/qwindowswindow.h -+++ b/src/plugins/platforms/windows/qwindowswindow.h -@@ -353,6 +353,10 @@ private: - inline void setWindowState_sys(Qt::WindowStates 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/platformthemes/gtk3/qgtk3dialoghelpers.cpp b/src/plugins/platformthemes/gtk3/qgtk3dialoghelpers.cpp -index c64a02fa0c..8207762022 100644 ---- a/src/plugins/platformthemes/gtk3/qgtk3dialoghelpers.cpp -+++ b/src/plugins/platformthemes/gtk3/qgtk3dialoghelpers.cpp -@@ -45,6 +45,7 @@ - #include - #include - #include -+#include - - #include - #include -@@ -57,6 +58,16 @@ - - QT_BEGIN_NAMESPACE - -+// GTK file chooser image preview: thanks to Chromium -+ -+// The size of the preview we display for selected image files. We set height -+// larger than width because generally there is more free space vertically -+// than horiztonally (setting the preview image will alway expand the width of -+// the dialog, but usually not the height). The image's aspect ratio will always -+// be preserved. -+#define PREVIEW_WIDTH 256 -+#define PREVIEW_HEIGHT 512 -+ - class QGtk3Dialog : public QWindow - { - Q_OBJECT -@@ -77,18 +88,24 @@ Q_SIGNALS: - - protected: - static void onResponse(QGtk3Dialog *dialog, int response); -+ static void onUpdatePreview(QGtk3Dialog *dialog); - - private slots: - void onParentWindowDestroyed(); - - private: - GtkWidget *gtkWidget; -+ GtkWidget *previewWidget; - }; - - QGtk3Dialog::QGtk3Dialog(GtkWidget *gtkWidget) : gtkWidget(gtkWidget) - { - g_signal_connect_swapped(G_OBJECT(gtkWidget), "response", G_CALLBACK(onResponse), this); - g_signal_connect(G_OBJECT(gtkWidget), "delete-event", G_CALLBACK(gtk_widget_hide_on_delete), NULL); -+ -+ previewWidget = gtk_image_new(); -+ g_signal_connect_swapped(G_OBJECT(gtkWidget), "update-preview", G_CALLBACK(onUpdatePreview), this); -+ gtk_file_chooser_set_preview_widget(GTK_FILE_CHOOSER(gtkWidget), previewWidget); - } - - QGtk3Dialog::~QGtk3Dialog() -@@ -162,6 +179,32 @@ void QGtk3Dialog::onResponse(QGtk3Dialog *dialog, int response) - emit dialog->reject(); - } - -+void QGtk3Dialog::onUpdatePreview(QGtk3Dialog *dialog) { -+ gchar *filename = gtk_file_chooser_get_preview_filename(GTK_FILE_CHOOSER(dialog->gtkWidget)); -+ if (!filename) { -+ gtk_file_chooser_set_preview_widget_active(GTK_FILE_CHOOSER(dialog->gtkWidget), false); -+ return; -+ } -+ -+ // Don't attempt to open anything which isn't a regular file. If a named pipe, -+ // this may hang. See https://crbug.com/534754. -+ QFileInfo fileinfo(filename); -+ if (!fileinfo.exists() || !fileinfo.isFile()) { -+ g_free(filename); -+ gtk_file_chooser_set_preview_widget_active(GTK_FILE_CHOOSER(dialog->gtkWidget), false); -+ return; -+ } -+ -+ // This will preserve the image's aspect ratio. -+ GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file_at_size(filename, PREVIEW_WIDTH, PREVIEW_HEIGHT, 0); -+ g_free(filename); -+ if (pixbuf) { -+ gtk_image_set_from_pixbuf(GTK_IMAGE(dialog->previewWidget), pixbuf); -+ g_object_unref(pixbuf); -+ } -+ gtk_file_chooser_set_preview_widget_active(GTK_FILE_CHOOSER(dialog->gtkWidget), pixbuf ? true : false); -+} -+ - void QGtk3Dialog::onParentWindowDestroyed() - { - // The QGtk3*DialogHelper classes own this object. Make sure the parent doesn't delete it. -diff --git a/src/plugins/platformthemes/gtk3/qgtk3theme.cpp b/src/plugins/platformthemes/gtk3/qgtk3theme.cpp -index 077955eb4e..5c8a3dddf7 100644 ---- a/src/plugins/platformthemes/gtk3/qgtk3theme.cpp -+++ b/src/plugins/platformthemes/gtk3/qgtk3theme.cpp -@@ -153,7 +153,7 @@ bool QGtk3Theme::usePlatformNativeDialog(DialogType type) const - case ColorDialog: - return true; - case FileDialog: -- return useNativeFileDialog(); -+ return true; - case FontDialog: - return true; - default: -@@ -167,8 +167,6 @@ QPlatformDialogHelper *QGtk3Theme::createPlatformDialogHelper(DialogType type) c - case ColorDialog: - return new QGtk3ColorDialogHelper; - case FileDialog: -- if (!useNativeFileDialog()) -- return nullptr; - return new QGtk3FileDialogHelper; - case FontDialog: - return new QGtk3FontDialogHelper; -diff --git a/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportaltheme.cpp b/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportaltheme.cpp -index fb65f6d909..66c3a54a07 100644 ---- a/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportaltheme.cpp -+++ b/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportaltheme.cpp -@@ -57,9 +57,11 @@ public: - ~QXdgDesktopPortalThemePrivate() - { - delete baseTheme; -+ delete gtkTheme; - } - - QPlatformTheme *baseTheme; -+ QPlatformTheme *gtkTheme; - }; - - QXdgDesktopPortalTheme::QXdgDesktopPortalTheme() -@@ -85,11 +87,17 @@ QXdgDesktopPortalTheme::QXdgDesktopPortalTheme() - break; - } - // No error message; not having a theme plugin is allowed. -+ -+ // Try to use gtk's open directory dialog if there are no fallback theme -+ d->gtkTheme = QPlatformThemeFactory::create(QLatin1String("gtk3"), nullptr); - } - - // 3) Fall back on the built-in "null" platform theme. - if (!d->baseTheme) - d->baseTheme = new QPlatformTheme; -+ -+ if (!d->gtkTheme) -+ d->gtkTheme = new QPlatformTheme; - } - - QPlatformMenuItem* QXdgDesktopPortalTheme::createPlatformMenuItem() const -@@ -133,6 +141,8 @@ QPlatformDialogHelper* QXdgDesktopPortalTheme::createPlatformDialogHelper(Dialog - if (type == FileDialog) { - if (d->baseTheme->usePlatformNativeDialog(type)) - return new QXdgDesktopPortalFileDialog(static_cast(d->baseTheme->createPlatformDialogHelper(type))); -+ else if (d->gtkTheme->usePlatformNativeDialog(type)) -+ return new QXdgDesktopPortalFileDialog(static_cast(d->gtkTheme->createPlatformDialogHelper(type))); - - return new QXdgDesktopPortalFileDialog; - } -diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp -index bf339ca5c5..4cdf9189ad 100644 ---- a/src/widgets/kernel/qwidget.cpp -+++ b/src/widgets/kernel/qwidget.cpp -@@ -5161,6 +5161,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; -@@ -5182,6 +5193,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; - } - -@@ -5214,6 +5229,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) -@@ -8968,7 +8986,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))) { - 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_qpa.cpp b/src/widgets/util/qsystemtrayicon_qpa.cpp -index c0bf058681..1c8b627d01 100644 ---- a/src/widgets/util/qsystemtrayicon_qpa.cpp -+++ b/src/widgets/util/qsystemtrayicon_qpa.cpp -@@ -93,6 +93,10 @@ void QSystemTrayIconPrivate::updateMenu_sys() - if (qpa_sys && menu) { - addPlatformMenu(menu); - qpa_sys->updateMenu(menu->platformMenu()); -+ -+ // Patch: Create a rich os x tray icon (pixel-perfect, theme switching). -+ } else if (qpa_sys) { -+ qpa_sys->updateMenu(nullptr); - } - #endif - } -diff --git a/src/widgets/widgets/qabstractscrollarea.cpp b/src/widgets/widgets/qabstractscrollarea.cpp -index 598d173144..fd2e636563 100644 ---- a/src/widgets/widgets/qabstractscrollarea.cpp -+++ b/src/widgets/widgets/qabstractscrollarea.cpp -@@ -655,15 +655,21 @@ 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/Telegram/Patches/qtstyleplugins.diff b/Telegram/Patches/qtstyleplugins.diff deleted file mode 100644 index c64624f6e..000000000 --- a/Telegram/Patches/qtstyleplugins.diff +++ /dev/null @@ -1,87 +0,0 @@ -diff --git a/src/plugins/platformthemes/gtk2/qgtk2dialoghelpers.cpp b/src/plugins/platformthemes/gtk2/qgtk2dialoghelpers.cpp -index 62e5dd2..3e609f7 100644 ---- a/src/plugins/platformthemes/gtk2/qgtk2dialoghelpers.cpp -+++ b/src/plugins/platformthemes/gtk2/qgtk2dialoghelpers.cpp -@@ -38,6 +38,7 @@ - #include - #include - #include -+#include - - #include - #include -@@ -50,6 +51,16 @@ - - QT_BEGIN_NAMESPACE - -+// GTK file chooser image preview: thanks to Chromium -+ -+// The size of the preview we display for selected image files. We set height -+// larger than width because generally there is more free space vertically -+// than horiztonally (setting the preview image will alway expand the width of -+// the dialog, but usually not the height). The image's aspect ratio will always -+// be preserved. -+#define PREVIEW_WIDTH 256 -+#define PREVIEW_HEIGHT 512 -+ - class QGtk2Dialog : public QWindow - { - Q_OBJECT -@@ -70,18 +81,24 @@ Q_SIGNALS: - - protected: - static void onResponse(QGtk2Dialog *dialog, int response); -+ static void onUpdatePreview(QGtk2Dialog *dialog); - - private slots: - void onParentWindowDestroyed(); - - private: - GtkWidget *gtkWidget; -+ GtkWidget *previewWidget; - }; - - QGtk2Dialog::QGtk2Dialog(GtkWidget *gtkWidget) : gtkWidget(gtkWidget) - { - g_signal_connect_swapped(G_OBJECT(gtkWidget), "response", G_CALLBACK(onResponse), this); - g_signal_connect(G_OBJECT(gtkWidget), "delete-event", G_CALLBACK(gtk_widget_hide_on_delete), NULL); -+ -+ previewWidget = gtk_image_new(); -+ g_signal_connect_swapped(G_OBJECT(gtkWidget), "update-preview", G_CALLBACK(onUpdatePreview), this); -+ gtk_file_chooser_set_preview_widget(GTK_FILE_CHOOSER(gtkWidget), previewWidget); - } - - QGtk2Dialog::~QGtk2Dialog() -@@ -151,6 +168,32 @@ void QGtk2Dialog::onResponse(QGtk2Dialog *dialog, int response) - emit dialog->reject(); - } - -+void QGtk2Dialog::onUpdatePreview(QGtk2Dialog *dialog) { -+ gchar *filename = gtk_file_chooser_get_preview_filename(GTK_FILE_CHOOSER(dialog->gtkWidget)); -+ if (!filename) { -+ gtk_file_chooser_set_preview_widget_active(GTK_FILE_CHOOSER(dialog->gtkWidget), false); -+ return; -+ } -+ -+ // Don't attempt to open anything which isn't a regular file. If a named pipe, -+ // this may hang. See https://crbug.com/534754. -+ QFileInfo fileinfo(filename); -+ if (!fileinfo.exists() || !fileinfo.isFile()) { -+ g_free(filename); -+ gtk_file_chooser_set_preview_widget_active(GTK_FILE_CHOOSER(dialog->gtkWidget), false); -+ return; -+ } -+ -+ // This will preserve the image's aspect ratio. -+ GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file_at_size(filename, PREVIEW_WIDTH, PREVIEW_HEIGHT, 0); -+ g_free(filename); -+ if (pixbuf) { -+ gtk_image_set_from_pixbuf(GTK_IMAGE(dialog->previewWidget), pixbuf); -+ g_object_unref(pixbuf); -+ } -+ gtk_file_chooser_set_preview_widget_active(GTK_FILE_CHOOSER(dialog->gtkWidget), pixbuf ? true : false); -+} -+ - void QGtk2Dialog::onParentWindowDestroyed() - { - // The QGtk2*DialogHelper classes own this object. Make sure the parent doesn't delete it. diff --git a/Telegram/Patches/qtwayland_5_12_8.diff b/Telegram/Patches/qtwayland_5_12_8.diff deleted file mode 100644 index 98b5d1257..000000000 --- a/Telegram/Patches/qtwayland_5_12_8.diff +++ /dev/null @@ -1,19 +0,0 @@ -diff --git a/src/client/qwaylandintegration.cpp b/src/client/qwaylandintegration.cpp -index 46bef294..845bb038 100644 ---- a/src/client/qwaylandintegration.cpp -+++ b/src/client/qwaylandintegration.cpp -@@ -293,12 +293,12 @@ QWaylandDisplay *QWaylandIntegration::display() const - - QStringList QWaylandIntegration::themeNames() const - { -- return GenericWaylandTheme::themeNames(); -+ return QGenericUnixTheme::themeNames(); - } - - QPlatformTheme *QWaylandIntegration::createPlatformTheme(const QString &name) const - { -- return GenericWaylandTheme::createUnixTheme(name); -+ return QGenericUnixTheme::createUnixTheme(name); - } - - // May be called from non-GUI threads diff --git a/docs/building-cmake.md b/docs/building-cmake.md index aff7821fb..8a40103c7 100644 --- a/docs/building-cmake.md +++ b/docs/building-cmake.md @@ -54,7 +54,7 @@ Go to ***BuildPath*** and run git clone https://github.com/desktop-app/patches.git cd patches - git checkout b08b497 + git checkout 3e9be0f cd ../ git clone https://github.com/xiph/opus