diff -Nru telegram-desktop-1.5.8/.appveyor/install.bat telegram-desktop-1.5.11/.appveyor/install.bat --- telegram-desktop-1.5.8/.appveyor/install.bat 2019-01-21 17:28:45.000000000 +0000 +++ telegram-desktop-1.5.11/.appveyor/install.bat 2019-02-01 12:51:46.000000000 +0000 @@ -72,10 +72,6 @@ set TDESKTOP_BUILD_DEFINES=%TDESKTOP_BUILD_DEFINES%,TDESKTOP_DISABLE_DESKTOP_FILE_GENERATION ) - echo %BUILD_VERSION% | findstr /C:"disable_unity_integration">nul && ( - set TDESKTOP_BUILD_DEFINES=%TDESKTOP_BUILD_DEFINES%,TDESKTOP_DISABLE_UNITY_INTEGRATION - ) - echo %BUILD_VERSION% | findstr /C:"disable_gtk_integration">nul && ( set TDESKTOP_BUILD_DEFINES=%TDESKTOP_BUILD_DEFINES%,TDESKTOP_DISABLE_GTK_INTEGRATION ) diff -Nru telegram-desktop-1.5.8/changelog.txt telegram-desktop-1.5.11/changelog.txt --- telegram-desktop-1.5.8/changelog.txt 2019-01-21 17:28:45.000000000 +0000 +++ telegram-desktop-1.5.11/changelog.txt 2019-02-01 12:51:46.000000000 +0000 @@ -1,3 +1,15 @@ +1.5.11 (01.02.19) + +- Bug fixes and other minor improvements. + +1.5.10 (01.02.19) + +- Bug fixes and other minor improvements. + +1.5.9 (31.01.19) + +- Bug fixes and other minor improvements. + 1.5.8 (21.01.19) - Global permissions for groups. Restrict all members in any group from posting certain types of content. diff -Nru telegram-desktop-1.5.8/debian/changelog telegram-desktop-1.5.11/debian/changelog --- telegram-desktop-1.5.8/debian/changelog 2019-01-24 18:25:39.000000000 +0000 +++ telegram-desktop-1.5.11/debian/changelog 2019-02-03 18:30:53.000000000 +0000 @@ -1,3 +1,10 @@ +telegram-desktop (1.5.11-1) unstable; urgency=medium + + * New upstream release. + * Refresh patches to fit new version. + + -- Nicholas Guriev Sun, 03 Feb 2019 21:30:53 +0300 + telegram-desktop (1.5.8-1) unstable; urgency=medium * New upstream release. diff -Nru telegram-desktop-1.5.8/debian/copyright telegram-desktop-1.5.11/debian/copyright --- telegram-desktop-1.5.8/debian/copyright 2019-01-24 18:25:39.000000000 +0000 +++ telegram-desktop-1.5.11/debian/copyright 2019-02-03 18:30:53.000000000 +0000 @@ -24,7 +24,8 @@ Files: Telegram/Resources/fonts/OpenSans-Regular.ttf Telegram/Resources/fonts/OpenSans-Bold.ttf Telegram/Resources/fonts/OpenSans-Semibold.ttf -Copyright: Steve Matteson +Author: Steve Matteson +Copyright: 2010-2011 Google Corporation License: Apache-2.0 Files: Telegram/Resources/emoji_autocomplete.json @@ -32,6 +33,11 @@ License: Expat Comment: See https://github.com/emojione/emojione/tree/master/extras/alpha-codes +Files: Telegram/SourceFiles/boxes/mute_settings_box.h + Telegram/SourceFiles/boxes/mute_settings_box.cpp +Copyright: 2017 Nicholas Guriev +License: Public-domain + Files: Telegram/gyp/PrecompiledHeader.cmake Copyright: 2009-2013 Lars Christensen License: Expat @@ -57,9 +63,7 @@ https://github.com/telegramdesktop/tdesktop/pull/4505#event-1746102406 Files: debian/* - Telegram/SourceFiles/boxes/mute_settings_box.h - Telegram/SourceFiles/boxes/mute_settings_box.cpp -Copyright: 2016-2018 Nicholas Guriev +Copyright: 2016-2019 Nicholas Guriev License: Public-domain Comment: Contributing policy - https://cla-assistant.io/telegramdesktop/tdesktop diff -Nru telegram-desktop-1.5.8/debian/patches/Modify-build-scripts.patch telegram-desktop-1.5.11/debian/patches/Modify-build-scripts.patch --- telegram-desktop-1.5.8/debian/patches/Modify-build-scripts.patch 2018-12-19 10:46:53.000000000 +0000 +++ telegram-desktop-1.5.11/debian/patches/Modify-build-scripts.patch 2019-02-03 18:30:53.000000000 +0000 @@ -48,7 +48,7 @@ int (*TestForkedMethod)()/* = nullptr*/; --- a/Telegram/SourceFiles/config.h +++ b/Telegram/SourceFiles/config.h -@@ -225,7 +225,7 @@ constexpr auto ApiHash = "344583e45741c4 +@@ -207,7 +207,7 @@ constexpr auto ApiHash = "344583e45741c4 #endif // TDESKTOP_API_ID && TDESKTOP_API_HASH #if Q_BYTE_ORDER == Q_BIG_ENDIAN @@ -69,17 +69,6 @@ const auto launcher = Core::Launcher::Create(argc, argv); return launcher ? launcher->exec() : 1; } ---- a/Telegram/SourceFiles/platform/linux/linux_libs.h -+++ b/Telegram/SourceFiles/platform/linux/linux_libs.h -@@ -21,7 +21,7 @@ extern "C" { - } // extern "C" - - #ifndef TDESKTOP_DISABLE_UNITY_INTEGRATION --#include -+typedef void UnityLauncherEntry; - #endif // !TDESKTOP_DISABLE_UNITY_INTEGRATION - #endif // !TDESKTOP_DISABLE_GTK_INTEGRATION - --- a/Telegram/SourceFiles/rpl/details/callable.h +++ b/Telegram/SourceFiles/rpl/details/callable.h @@ -7,7 +7,6 @@ https://github.com/telegramdesktop/tdesk @@ -216,7 +205,7 @@ 'sources': [ --- a/Telegram/gyp/lib_base.gyp +++ b/Telegram/gyp/lib_base.gyp -@@ -29,27 +29,19 @@ +@@ -27,27 +27,19 @@ 'pch_source': '<(src_loc)/base/base_pch.cpp', 'pch_header': '<(src_loc)/base/base_pch.h', }, @@ -247,7 +236,7 @@ '<(src_loc)/base/concurrent_timer.h', --- a/Telegram/gyp/lib_export.gyp +++ b/Telegram/gyp/lib_export.gyp -@@ -48,10 +48,7 @@ +@@ -46,10 +46,7 @@ 'include_dirs': [ '<(src_loc)', '<(SHARED_INTERMEDIATE_DIR)', @@ -261,7 +250,7 @@ '<(src_loc)/export/export_api_wrap.cpp', --- a/Telegram/gyp/lib_storage.gyp +++ b/Telegram/gyp/lib_storage.gyp -@@ -29,9 +29,6 @@ +@@ -27,9 +27,6 @@ 'pch_source': '<(src_loc)/storage/storage_pch.cpp', 'pch_header': '<(src_loc)/storage/storage_pch.h', }, @@ -271,7 +260,7 @@ 'dependencies': [ 'crl.gyp:crl', 'lib_base.gyp:lib_base', -@@ -43,11 +40,7 @@ +@@ -41,11 +38,7 @@ 'include_dirs': [ '<(src_loc)', '<(SHARED_INTERMEDIATE_DIR)', @@ -537,8 +526,8 @@ 'cflags_cc': [ ' --- a/Telegram/SourceFiles/core/file_utilities.cpp +++ b/Telegram/SourceFiles/core/file_utilities.cpp -@@ -336,3 +336,20 @@ bool GetDefault( +@@ -344,3 +344,20 @@ bool GetDefault( } // namespace internal } // namespace FileDialog @@ -68,15 +68,15 @@ +#include "core/file_utilities.h" #include "core/main_queue_processor.h" #include "core/update_checker.h" - #include "base/concurrent_timer.h" -@@ -38,6 +39,7 @@ void Launcher::init() { + #include "core/sandbox.h" +@@ -207,6 +208,7 @@ void Launcher::init() { prepareSettings(); - QCoreApplication::setApplicationName(qsl("TelegramDesktop")); + QApplication::setApplicationName(qsl("TelegramDesktop")); + Resources::LoadAllData(); // should be called after setting an application name #ifndef OS_MAC_OLD - QCoreApplication::setAttribute(Qt::AA_DisableHighDpiScaling, true); + QApplication::setAttribute(Qt::AA_DisableHighDpiScaling, true); --- a/Telegram/gyp/Telegram.gyp +++ b/Telegram/gyp/Telegram.gyp @@ -52,6 +52,7 @@ diff -Nru telegram-desktop-1.5.8/docs/building-cmake.md telegram-desktop-1.5.11/docs/building-cmake.md --- telegram-desktop-1.5.8/docs/building-cmake.md 2019-01-21 17:28:45.000000000 +0000 +++ telegram-desktop-1.5.11/docs/building-cmake.md 2019-02-01 12:51:46.000000000 +0000 @@ -22,7 +22,7 @@ sudo add-apt-repository --remove ppa:ubuntu-toolchain-r/test sudo add-apt-repository --remove ppa:george-edison55/cmake-3.x - sudo apt-get install git libexif-dev liblzma-dev libz-dev libssl-dev libappindicator-dev libunity-dev libicu-dev libdee-dev libdrm-dev dh-autoreconf autoconf automake build-essential libass-dev libfreetype6-dev libgpac-dev libsdl1.2-dev libtheora-dev libtool libva-dev libvdpau-dev libvorbis-dev libxcb1-dev libxcb-image0-dev libxcb-shm0-dev libxcb-xfixes0-dev libxcb-keysyms1-dev libxcb-icccm4-dev libxcb-render-util0-dev libxcb-util0-dev libxrender-dev libasound-dev libpulse-dev libxcb-sync0-dev libxcb-randr0-dev libx11-xcb-dev libffi-dev libncurses5-dev pkg-config texi2html zlib1g-dev yasm cmake xutils-dev bison python-xcbgen + sudo apt-get install git libexif-dev liblzma-dev libz-dev libssl-dev libappindicator-dev libicu-dev libdee-dev libdrm-dev dh-autoreconf autoconf automake build-essential libass-dev libfreetype6-dev libgpac-dev libsdl1.2-dev libtheora-dev libtool libva-dev libvdpau-dev libvorbis-dev libxcb1-dev libxcb-image0-dev libxcb-shm0-dev libxcb-xfixes0-dev libxcb-keysyms1-dev libxcb-icccm4-dev libxcb-render-util0-dev libxcb-util0-dev libxrender-dev libasound-dev libpulse-dev libxcb-sync0-dev libxcb-randr0-dev libx11-xcb-dev libffi-dev libncurses5-dev pkg-config texi2html zlib1g-dev yasm cmake xutils-dev bison python-xcbgen You can set the multithreaded make parameter by running diff -Nru telegram-desktop-1.5.8/snap/snapcraft.yaml telegram-desktop-1.5.11/snap/snapcraft.yaml --- telegram-desktop-1.5.8/snap/snapcraft.yaml 2019-01-21 17:28:45.000000000 +0000 +++ telegram-desktop-1.5.11/snap/snapcraft.yaml 2019-02-01 12:51:46.000000000 +0000 @@ -72,7 +72,7 @@ - libicu-dev - liblzma-dev - libssl-dev - - libunity-dev + - libdee-dev - zlib1g-dev gyp-file: Telegram/gyp/Telegram.gyp build-type: 'Release' @@ -133,7 +133,6 @@ - libappindicator3-1 - libnotify4 - libpulse0 - - libunity9 after: [desktop-gtk3] stage: - -./usr/share/fonts/** diff -Nru telegram-desktop-1.5.8/Telegram/build/updates.py telegram-desktop-1.5.11/Telegram/build/updates.py --- telegram-desktop-1.5.8/Telegram/build/updates.py 2019-01-21 17:28:45.000000000 +0000 +++ telegram-desktop-1.5.11/Telegram/build/updates.py 2019-02-01 12:51:46.000000000 +0000 @@ -107,6 +107,8 @@ print('Finished.') finish(0) +commandPath = scriptPath + '/../../out/Debug/' + outputFolder + '/command.txt' + if composing: templatePath = scriptPath + '/../../../TelegramPrivate/updates_template.txt' if not os.path.exists(templatePath): @@ -147,16 +149,17 @@ changelog = '\n'.join(commits) print('\n\nReady! File: ' + archive + '\nChangelog:\n' + changelog) with open(templatePath, 'r') as template: - with open(scriptPath + '/../../out/Debug/' + outputFolder + '/command.txt', 'w') as f: + with open(commandPath, 'w') as f: for line in template: if line.startswith('//'): continue line = line.replace('{path}', scriptPath + '/../../out/Debug/' + outputFolder + '/' + archive) line = line.replace('{caption}', 'TDesktop at ' + today.replace('_', '.') + ':\n\n' + changelog) f.write(line) + print('\n\nEdit:\n') + print('vi ' + commandPath) finish(0) -commandPath = scriptPath + '/../../out/Debug/' + outputFolder + '/command.txt' if not os.path.exists(commandPath): print('[ERROR] Command file not found.') finish(1) diff -Nru telegram-desktop-1.5.8/Telegram/build/version telegram-desktop-1.5.11/Telegram/build/version --- telegram-desktop-1.5.8/Telegram/build/version 2019-01-21 17:28:45.000000000 +0000 +++ telegram-desktop-1.5.11/Telegram/build/version 2019-02-01 12:51:46.000000000 +0000 @@ -1,6 +1,6 @@ -AppVersion 1005008 +AppVersion 1005011 AppVersionStrMajor 1.5 -AppVersionStrSmall 1.5.8 -AppVersionStr 1.5.8 +AppVersionStrSmall 1.5.11 +AppVersionStr 1.5.11 BetaChannel 0 AlphaVersion 0 diff -Nru telegram-desktop-1.5.8/Telegram/gyp/telegram_sources.txt telegram-desktop-1.5.11/Telegram/gyp/telegram_sources.txt --- telegram-desktop-1.5.8/Telegram/gyp/telegram_sources.txt 2019-01-21 17:28:45.000000000 +0000 +++ telegram-desktop-1.5.11/Telegram/gyp/telegram_sources.txt 2019-02-01 12:51:46.000000000 +0000 @@ -113,6 +113,8 @@ <(src_loc)/chat_helpers/tabbed_section.h <(src_loc)/chat_helpers/tabbed_selector.cpp <(src_loc)/chat_helpers/tabbed_selector.h +<(src_loc)/core/application.cpp +<(src_loc)/core/application.h <(src_loc)/core/changelogs.cpp <(src_loc)/core/changelogs.h <(src_loc)/core/click_handler.cpp @@ -138,6 +140,8 @@ <(src_loc)/core/media_active_cache.h <(src_loc)/core/mime_type.cpp <(src_loc)/core/mime_type.h +<(src_loc)/core/sandbox.cpp +<(src_loc)/core/sandbox.h <(src_loc)/core/shortcuts.cpp <(src_loc)/core/shortcuts.h <(src_loc)/core/update_checker.cpp @@ -271,6 +275,8 @@ <(src_loc)/history/media/history_media_sticker.cpp <(src_loc)/history/media/history_media_video.h <(src_loc)/history/media/history_media_video.cpp +<(src_loc)/history/media/history_media_wall_paper.h +<(src_loc)/history/media/history_media_wall_paper.cpp <(src_loc)/history/media/history_media_web_page.h <(src_loc)/history/media/history_media_web_page.cpp <(src_loc)/history/view/history_view_context_menu.cpp @@ -799,8 +805,6 @@ <(src_loc)/apiwrap.h <(src_loc)/app.cpp <(src_loc)/app.h -<(src_loc)/application.cpp -<(src_loc)/application.h <(src_loc)/auth_session.cpp <(src_loc)/auth_session.h <(src_loc)/config.h @@ -818,8 +822,6 @@ <(src_loc)/mainwindow.h <(src_loc)/mediaview.cpp <(src_loc)/mediaview.h -<(src_loc)/messenger.cpp -<(src_loc)/messenger.h <(src_loc)/observer_peer.cpp <(src_loc)/observer_peer.h <(src_loc)/qt_static_plugins.cpp diff -Nru telegram-desktop-1.5.8/Telegram/Patches/qtbase_5_6_2.diff telegram-desktop-1.5.11/Telegram/Patches/qtbase_5_6_2.diff --- telegram-desktop-1.5.8/Telegram/Patches/qtbase_5_6_2.diff 2019-01-21 17:28:45.000000000 +0000 +++ telegram-desktop-1.5.11/Telegram/Patches/qtbase_5_6_2.diff 2019-02-01 12:51:46.000000000 +0000 @@ -1,5 +1,5 @@ diff --git a/mkspecs/common/msvc-desktop.conf b/mkspecs/common/msvc-desktop.conf -index eec9e1f..7ae53c7 100644 +index eec9e1f688..7ae53c7a1e 100644 --- a/mkspecs/common/msvc-desktop.conf +++ b/mkspecs/common/msvc-desktop.conf @@ -30,9 +30,10 @@ QMAKE_YACCFLAGS = -d @@ -17,7 +17,7 @@ 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 391fbcc..d07802b 100644 +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) @@ -36,7 +36,7 @@ // 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 14e4fd1..0619a17 100644 +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[] = { @@ -50,7 +50,7 @@ { 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 2d00b9d..eeba86e 100644 +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"; @@ -64,7 +64,7 @@ qreal result = 1; if (qEnvironmentVariableIsSet(scaleFactorEnvVar)) { diff --git a/src/gui/kernel/qplatformdialoghelper.h b/src/gui/kernel/qplatformdialoghelper.h -index 5b2f4ec..790db46 100644 +index 5b2f4ece77..790db46d25 100644 --- a/src/gui/kernel/qplatformdialoghelper.h +++ b/src/gui/kernel/qplatformdialoghelper.h @@ -386,6 +386,10 @@ public: @@ -79,7 +79,7 @@ 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 bcd29b6..bcb0672 100644 +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) @@ -93,7 +93,7 @@ QCursor *c = QGuiApplication::overrideCursor(); if (!c && hasCursor) diff --git a/src/gui/painting/qpaintengine_p.h b/src/gui/painting/qpaintengine_p.h -index 918c989..4158259 100644 +index 918c98997b..4158259743 100644 --- a/src/gui/painting/qpaintengine_p.h +++ b/src/gui/painting/qpaintengine_p.h @@ -80,8 +80,18 @@ public: @@ -117,7 +117,7 @@ // Make sure we're inside the viewport. diff --git a/src/gui/text/qtextengine_p.h b/src/gui/text/qtextengine_p.h -index 7e507bb..936e7a9 100644 +index 7e507bba2d..936e7a92cb 100644 --- a/src/gui/text/qtextengine_p.h +++ b/src/gui/text/qtextengine_p.h @@ -283,7 +283,8 @@ private: @@ -131,7 +131,7 @@ public: inline QTextItemInt() diff --git a/src/gui/text/qtextlayout.cpp b/src/gui/text/qtextlayout.cpp -index aca475a..5fa0be2 100644 +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 @@ -208,7 +208,7 @@ static const QFixed RightBearingNotCalculated; diff --git a/src/gui/text/qtextlayout.h b/src/gui/text/qtextlayout.h -index f74d4d4..8ad672c 100644 +index f74d4d4229..8ad672c9fe 100644 --- a/src/gui/text/qtextlayout.h +++ b/src/gui/text/qtextlayout.h @@ -196,6 +196,9 @@ private: @@ -222,7 +222,7 @@ diff --git a/src/network/access/qhttpnetworkconnection.cpp b/src/network/access/qhttpnetworkconnection.cpp -index c4cb8e6..45793e3 100644 +index c4cb8e65c0..45793e364f 100644 --- a/src/network/access/qhttpnetworkconnection.cpp +++ b/src/network/access/qhttpnetworkconnection.cpp @@ -110,6 +110,8 @@ QHttpNetworkConnectionPrivate::~QHttpNetworkConnectionPrivate() @@ -235,7 +235,7 @@ delete channels[i].socket; } diff --git a/src/network/socket/qnativesocketengine_win.cpp b/src/network/socket/qnativesocketengine_win.cpp -index 41834b2..8cdf4ab 100644 +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 @@ -253,7 +253,7 @@ setError(QAbstractSocket::NetworkError, AddressNotAvailableErrorString); socketState = QAbstractSocket::UnconnectedState; diff --git a/src/platformsupport/dbustray/qdbustrayicon.cpp b/src/platformsupport/dbustray/qdbustrayicon.cpp -index 4d6e707..9bdb0be 100644 +index 4d6e70720d..9bdb0beb67 100644 --- a/src/platformsupport/dbustray/qdbustrayicon.cpp +++ b/src/platformsupport/dbustray/qdbustrayicon.cpp @@ -58,9 +58,18 @@ QT_BEGIN_NAMESPACE @@ -290,7 +290,7 @@ } if (!necessary) diff --git a/src/platformsupport/fontdatabases/basic/qbasicfontdatabase.cpp b/src/platformsupport/fontdatabases/basic/qbasicfontdatabase.cpp -index 728b166..1dc6459 100644 +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) @@ -388,7 +388,7 @@ 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 8ebabf3..7bb8abd 100644 +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) @@ -450,7 +450,7 @@ } populateFromPattern(pattern); diff --git a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm b/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm -index 566abf2..5c5fde9 100644 +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) @@ -482,7 +482,7 @@ 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 7b45958..2ed2fd9 100644 +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 @@ -496,7 +496,7 @@ QFontEngine *QCoreTextFontEngine::cloneWithSize(qreal pixelSize) const diff --git a/src/plugins/platforminputcontexts/compose/compose.pro b/src/plugins/platforminputcontexts/compose/compose.pro -index 86bdd47..9b9c8de 100644 +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 \ @@ -510,7 +510,7 @@ 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 d1bea9a..36a15a6 100644 +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() @@ -527,7 +527,7 @@ event.setCommitString(QChar(character)); QCoreApplication::sendEvent(m_focusObject, &event); diff --git a/src/plugins/platforminputcontexts/platforminputcontexts.pro b/src/plugins/platforminputcontexts/platforminputcontexts.pro -index faea54b..fe4a837 100644 +index faea54b874..fe4a837511 100644 --- a/src/plugins/platforminputcontexts/platforminputcontexts.pro +++ b/src/plugins/platforminputcontexts/platforminputcontexts.pro @@ -1,7 +1,8 @@ @@ -541,7 +541,7 @@ contains(QT_CONFIG, xcb-plugin): SUBDIRS += compose diff --git a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm -index caa8884..9dc3bc1 100644 +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 @@ -572,7 +572,7 @@ } diff --git a/src/plugins/platforms/cocoa/qcocoabackingstore.h b/src/plugins/platforms/cocoa/qcocoabackingstore.h -index 934f68a..3ece698 100644 +index 934f68ad18..3ece6984ac 100644 --- a/src/plugins/platforms/cocoa/qcocoabackingstore.h +++ b/src/plugins/platforms/cocoa/qcocoabackingstore.h @@ -64,6 +64,9 @@ public: @@ -586,7 +586,7 @@ QT_END_NAMESPACE diff --git a/src/plugins/platforms/cocoa/qcocoabackingstore.mm b/src/plugins/platforms/cocoa/qcocoabackingstore.mm -index ca92103..f27ea15 100644 +index ca92103826..f27ea15bad 100644 --- a/src/plugins/platforms/cocoa/qcocoabackingstore.mm +++ b/src/plugins/platforms/cocoa/qcocoabackingstore.mm @@ -38,7 +38,8 @@ @@ -624,7 +624,7 @@ 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 058209d..6af61e7 100644 +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 @@ -654,7 +654,7 @@ } diff --git a/src/plugins/platforms/cocoa/qcocoakeymapper.mm b/src/plugins/platforms/cocoa/qcocoakeymapper.mm -index c2d206f..9b97398 100644 +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() @@ -681,7 +681,7 @@ } return ret; diff --git a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm -index 8152c57..87ba2f3 100644 +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 @@ -821,7 +821,7 @@ } } diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm -index c0d5904..f3c2047 100644 +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) @@ -883,7 +883,7 @@ [iconButton setImage:image]; [image release]; diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm -index c67bcfd..2616f42 100644 +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 @@ -957,8 +957,19 @@ - (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 94bb71e..16ab51e 100644 +index 94bb71e429..16ab51e166 100644 --- a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp +++ b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp @@ -716,12 +716,20 @@ public: @@ -1163,7 +1174,7 @@ { 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 1e58b9b..1741c21 100644 +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 @@ -1178,7 +1189,7 @@ if (!kbItem.exists) return result; diff --git a/src/plugins/platforms/windows/qwindowsservices.cpp b/src/plugins/platforms/windows/qwindowsservices.cpp -index 1d23a9d..640cd42 100644 +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) @@ -1193,7 +1204,7 @@ // 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 b38d7c2..34f19c4 100644 +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() @@ -1247,7 +1258,7 @@ break; } diff --git a/src/plugins/platforms/windows/qwindowswindow.h b/src/plugins/platforms/windows/qwindowswindow.h -index 6fffa1e..cb1c9c1 100644 +index 6fffa1e6e9..cb1c9c1161 100644 --- a/src/plugins/platforms/windows/qwindowswindow.h +++ b/src/plugins/platforms/windows/qwindowswindow.h @@ -265,6 +265,10 @@ private: @@ -1262,7 +1273,7 @@ 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 09e7ecf..c0f15a4 100644 +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) @@ -1292,7 +1303,7 @@ break; } diff --git a/src/plugins/platforms/xcb/qxcbnativeinterface.h b/src/plugins/platforms/xcb/qxcbnativeinterface.h -index f88b710..6f818a5 100644 +index f88b710864..6f818a5a72 100644 --- a/src/plugins/platforms/xcb/qxcbnativeinterface.h +++ b/src/plugins/platforms/xcb/qxcbnativeinterface.h @@ -68,7 +68,10 @@ public: @@ -1308,7 +1319,7 @@ QXcbNativeInterface(); diff --git a/src/widgets/dialogs/qfiledialog.cpp b/src/widgets/dialogs/qfiledialog.cpp -index bc2de89..aa8f8df 100644 +index bc2de899f5..aa8f8df4ad 100644 --- a/src/widgets/dialogs/qfiledialog.cpp +++ b/src/widgets/dialogs/qfiledialog.cpp @@ -1200,6 +1200,15 @@ QList QFileDialogPrivate::userSelectedFiles() const @@ -1343,7 +1354,7 @@ 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 ffe49a2..42dc563 100644 +index ffe49a2dd2..42dc563c8a 100644 --- a/src/widgets/dialogs/qfiledialog.h +++ b/src/widgets/dialogs/qfiledialog.h @@ -108,6 +108,9 @@ public: @@ -1357,7 +1368,7 @@ QList selectedUrls() const; diff --git a/src/widgets/dialogs/qfiledialog_p.h b/src/widgets/dialogs/qfiledialog_p.h -index f610e46..547a646 100644 +index f610e46f83..547a64695a 100644 --- a/src/widgets/dialogs/qfiledialog_p.h +++ b/src/widgets/dialogs/qfiledialog_p.h @@ -123,6 +123,10 @@ public: @@ -1398,7 +1409,7 @@ { if (QPlatformFileDialogHelper *helper = platformFileDialogHelper()) diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp -index b1d80d7..42e32fd 100644 +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, @@ -1451,7 +1462,7 @@ || (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 704142f..7c4340e 100644 +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() @@ -1466,7 +1477,7 @@ } diff --git a/src/widgets/widgets/qabstractscrollarea.cpp b/src/widgets/widgets/qabstractscrollarea.cpp -index 2e2a042..472e377 100644 +index 2e2a042bf1..472e37722b 100644 --- a/src/widgets/widgets/qabstractscrollarea.cpp +++ b/src/widgets/widgets/qabstractscrollarea.cpp @@ -640,15 +640,22 @@ scrolling range. @@ -1497,7 +1508,7 @@ } diff --git a/src/widgets/widgets/qwidgetlinecontrol.cpp b/src/widgets/widgets/qwidgetlinecontrol.cpp -index daf9f00..57499dc 100644 +index daf9f00c46..57499dc4a4 100644 --- a/src/widgets/widgets/qwidgetlinecontrol.cpp +++ b/src/widgets/widgets/qwidgetlinecontrol.cpp @@ -40,6 +40,11 @@ @@ -1539,7 +1550,7 @@ #ifndef QT_NO_COMPLETER complete(event->key()); diff --git a/src/widgets/widgets/qwidgettextcontrol.cpp b/src/widgets/widgets/qwidgettextcontrol.cpp -index deca002..8a2023f 100644 +index deca002bf5..8a2023f503 100644 --- a/src/widgets/widgets/qwidgettextcontrol.cpp +++ b/src/widgets/widgets/qwidgettextcontrol.cpp @@ -71,6 +71,11 @@ diff -Nru telegram-desktop-1.5.8/Telegram/Resources/basic.style telegram-desktop-1.5.11/Telegram/Resources/basic.style --- telegram-desktop-1.5.8/Telegram/Resources/basic.style 2019-01-21 17:28:45.000000000 +0000 +++ telegram-desktop-1.5.11/Telegram/Resources/basic.style 2019-02-01 12:51:46.000000000 +0000 @@ -92,7 +92,7 @@ msgServiceNameFont: semiboldFont; msgServicePhotoWidth: 100px; msgDateFont: font(13px); -msgMinWidth: 190px; +msgMinWidth: 160px; msgPhotoSize: 33px; msgPhotoSkip: 40px; msgPadding: margins(13px, 7px, 13px, 8px); Binary files /tmp/tmpFEPiHQ/dlOIFeO1CF/telegram-desktop-1.5.8/Telegram/Resources/icons/dialogs_bot@2x.png and /tmp/tmpFEPiHQ/xmDpykG5Th/telegram-desktop-1.5.11/Telegram/Resources/icons/dialogs_bot@2x.png differ Binary files /tmp/tmpFEPiHQ/dlOIFeO1CF/telegram-desktop-1.5.8/Telegram/Resources/icons/dialogs_bot@3x.png and /tmp/tmpFEPiHQ/xmDpykG5Th/telegram-desktop-1.5.11/Telegram/Resources/icons/dialogs_bot@3x.png differ Binary files /tmp/tmpFEPiHQ/dlOIFeO1CF/telegram-desktop-1.5.8/Telegram/Resources/icons/dialogs_bot.png and /tmp/tmpFEPiHQ/xmDpykG5Th/telegram-desktop-1.5.11/Telegram/Resources/icons/dialogs_bot.png differ diff -Nru telegram-desktop-1.5.8/Telegram/Resources/langs/lang.strings telegram-desktop-1.5.11/Telegram/Resources/langs/lang.strings --- telegram-desktop-1.5.8/Telegram/Resources/langs/lang.strings 2019-01-21 17:28:45.000000000 +0000 +++ telegram-desktop-1.5.11/Telegram/Resources/langs/lang.strings 2019-02-01 12:51:46.000000000 +0000 @@ -145,8 +145,6 @@ "lng_sure_add_admin_invite_channel" = "This user is not a subscriber of this channel. Add them to the channel and promote them to admin?"; "lng_sure_add_admin_unremove" = "This user is currently restricted or removed. Are you sure you want to promote them?"; "lng_sure_ban_admin" = "This user is an admin. Are you sure you want to go ahead and restrict them?"; -"lng_sure_remove_user_group" = "Remove {user} from the group?"; -"lng_sure_remove_user_channel" = "Remove {user} from the channel?"; "lng_sure_enable_socks" = "Are you sure you want to enable this proxy?\n\nServer: {server}\nPort: {port}\n\nYou can change your proxy server later in the Settings (Connection Type)."; "lng_sure_enable" = "Enable"; @@ -398,10 +396,12 @@ "lng_theme_keep_changes" = "Keep changes"; "lng_theme_revert" = "Revert"; "lng_background_header" = "Background preview"; -"lng_background_text1" = "You can't swipe left or right to preview anything - this is tdesktop, sorry."; -"lng_background_text2" = "Sounds awful."; +"lng_background_text1" = "Ah, you kids today with techno music! You should enjoy the classics, like Hasselhoff!"; +"lng_background_text2" = "I can't even take you seriously right now."; "lng_background_bad_link" = "This background link appears to be invalid."; "lng_background_apply" = "Apply"; +"lng_background_share" = "Share"; +"lng_background_link_copied" = "Link copied to clipboard"; "lng_download_path_ask" = "Ask download path for each file"; "lng_download_path" = "Download path"; @@ -1035,6 +1035,7 @@ "lng_media_animation_title" = "Animated GIFs"; "lng_media_size_limit" = "Limit by size"; "lng_media_size_up_to" = "up to {size}"; +"lng_media_chat_background" = "Chat background"; "lng_emoji_category1" = "People"; "lng_emoji_category2" = "Nature"; diff -Nru telegram-desktop-1.5.8/Telegram/Resources/numbers.txt telegram-desktop-1.5.11/Telegram/Resources/numbers.txt --- telegram-desktop-1.5.8/Telegram/Resources/numbers.txt 2019-01-21 17:28:45.000000000 +0000 +++ telegram-desktop-1.5.11/Telegram/Resources/numbers.txt 2019-02-01 12:51:46.000000000 +0000 @@ -207,7 +207,7 @@ 52;MX;Mexico; 51;PE;Peru;51 XXX XXX XXX;11; 49;DE;Germany;49 XXX XXXXXXXX;13; -48;PL;Poland;48 XX XXX XXXX;11; +48;PL;Poland;48 XXX XXX XXX;11; 47;NO;Norway;47 XXXX XXXX;10; 46;SE;Sweden;46 XX XXX XXXX;11; 45;DK;Denmark;45 XXXX XXXX;10; diff -Nru telegram-desktop-1.5.8/Telegram/Resources/scheme.tl telegram-desktop-1.5.11/Telegram/Resources/scheme.tl --- telegram-desktop-1.5.8/Telegram/Resources/scheme.tl 2019-01-21 17:28:45.000000000 +0000 +++ telegram-desktop-1.5.11/Telegram/Resources/scheme.tl 2019-02-01 12:51:46.000000000 +0000 @@ -318,7 +318,7 @@ peerSettings#818426cd flags:# report_spam:flags.0?true = PeerSettings; -wallPaper#f04f91ec id:long flags:# creator:flags.0?true default:flags.1?true access_hash:long slug:string document:Document = WallPaper; +wallPaper#a437c3ed id:long flags:# creator:flags.0?true default:flags.1?true pattern:flags.3?true dark:flags.4?true access_hash:long slug:string document:Document settings:flags.2?WallPaperSettings = WallPaper; inputReportReasonSpam#58dbcab8 = ReportReason; inputReportReasonViolence#1e22c78d = ReportReason; @@ -1112,6 +1112,10 @@ account.wallPapersNotModified#1c199183 = account.WallPapers; account.wallPapers#702b65a9 hash:int wallpapers:Vector = account.WallPapers; +codeSettings#302f59f3 flags:# allow_flashcall:flags.0?true current_number:flags.1?true app_hash_persistent:flags.2?true app_hash:flags.3?string = CodeSettings; + +wallPaperSettings#a12f40b8 flags:# blur:flags.1?true motion:flags.2?true background_color:flags.0?int intensity:flags.3?int = WallPaperSettings; + ---functions--- invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X; @@ -1122,7 +1126,7 @@ invokeWithMessagesRange#365275f2 {X:Type} range:MessageRange query:!X = X; invokeWithTakeout#aca9fd2e {X:Type} takeout_id:long query:!X = X; -auth.sendCode#86aef0ec flags:# allow_flashcall:flags.0?true phone_number:string current_number:flags.0?Bool api_id:int api_hash:string = auth.SentCode; +auth.sendCode#a677244f phone_number:string api_id:int api_hash:string settings:CodeSettings = auth.SentCode; auth.signUp#1b067634 phone_number:string phone_code_hash:string phone_code:string first_name:string last_name:string = auth.Authorization; auth.signIn#bcd51581 phone_number:string phone_code_hash:string phone_code:string = auth.Authorization; auth.logOut#5717da40 = Bool; @@ -1154,7 +1158,7 @@ account.deleteAccount#418d4e0b reason:string = Bool; account.getAccountTTL#8fc711d = AccountDaysTTL; account.setAccountTTL#2442485e ttl:AccountDaysTTL = Bool; -account.sendChangePhoneCode#8e57deb flags:# allow_flashcall:flags.0?true phone_number:string current_number:flags.0?Bool = auth.SentCode; +account.sendChangePhoneCode#82574ae5 phone_number:string settings:CodeSettings = auth.SentCode; account.changePhone#70c32edb phone_number:string phone_code_hash:string phone_code:string = User; account.updateDeviceLocked#38df3532 period:int = Bool; account.getAuthorizations#e320c158 = account.Authorizations; @@ -1162,7 +1166,7 @@ account.getPassword#548a30f5 = account.Password; account.getPasswordSettings#9cd4eaf9 password:InputCheckPasswordSRP = account.PasswordSettings; account.updatePasswordSettings#a59b102f password:InputCheckPasswordSRP new_settings:account.PasswordInputSettings = Bool; -account.sendConfirmPhoneCode#1516d7bd flags:# allow_flashcall:flags.0?true hash:string current_number:flags.0?Bool = auth.SentCode; +account.sendConfirmPhoneCode#1b3faa88 hash:string settings:CodeSettings = auth.SentCode; account.confirmPhone#5f2178c3 phone_code_hash:string phone_code:string = Bool; account.getTmpPassword#449e0b51 password:InputCheckPasswordSRP period:int = account.TmpPassword; account.getWebAuthorizations#182e6d6f = account.WebAuthorizations; @@ -1174,7 +1178,7 @@ account.deleteSecureValue#b880bc4b types:Vector = Bool; account.getAuthorizationForm#b86ba8e1 bot_id:int scope:string public_key:string = account.AuthorizationForm; account.acceptAuthorization#e7027c94 bot_id:int scope:string public_key:string value_hashes:Vector credentials:SecureCredentialsEncrypted = Bool; -account.sendVerifyPhoneCode#823380b4 flags:# allow_flashcall:flags.0?true phone_number:string current_number:flags.0?Bool = auth.SentCode; +account.sendVerifyPhoneCode#a5a356f9 phone_number:string settings:CodeSettings = auth.SentCode; account.verifyPhone#4dd3a7f6 phone_number:string phone_code_hash:string phone_code:string = Bool; account.sendVerifyEmailCode#7011509f email:string = account.SentEmailCode; account.verifyEmail#ecba39db email:string code:string = Bool; @@ -1186,10 +1190,11 @@ account.getContactSignUpNotification#9f07c728 = Bool; account.setContactSignUpNotification#cff43f61 silent:Bool = Bool; account.getNotifyExceptions#53577479 flags:# compare_sound:flags.1?true peer:flags.0?InputNotifyPeer = Updates; -account.uploadWallPaper#c7ba9b4d file:InputFile mime_type:string = WallPaper; account.getWallPaper#fc8ddbea wallpaper:InputWallPaper = WallPaper; -account.saveWallPaper#189581b3 wallpaper:InputWallPaper unsave:Bool = Bool; -account.installWallPaper#4a0378ce wallpaper:InputWallPaper = Bool; +account.uploadWallPaper#dd853661 file:InputFile mime_type:string settings:WallPaperSettings = WallPaper; +account.saveWallPaper#6c5a5b37 wallpaper:InputWallPaper unsave:Bool settings:WallPaperSettings = Bool; +account.installWallPaper#feed5769 wallpaper:InputWallPaper settings:WallPaperSettings = Bool; +account.resetWallPapers#bb3b9804 = Bool; users.getUsers#d91a548 id:Vector = Vector; users.getFullUser#ca30a5b1 id:InputUser = UserFull; @@ -1418,4 +1423,4 @@ langpack.getLanguages#42c6978f lang_pack:string = Vector; langpack.getLanguage#6a596502 lang_pack:string lang_code:string = LangPackLanguage; -// LAYER 93 +// LAYER 95 diff -Nru telegram-desktop-1.5.8/Telegram/Resources/uwp/AppX/AppxManifest.xml telegram-desktop-1.5.11/Telegram/Resources/uwp/AppX/AppxManifest.xml --- telegram-desktop-1.5.8/Telegram/Resources/uwp/AppX/AppxManifest.xml 2019-01-21 17:28:45.000000000 +0000 +++ telegram-desktop-1.5.11/Telegram/Resources/uwp/AppX/AppxManifest.xml 2019-02-01 12:51:46.000000000 +0000 @@ -9,7 +9,7 @@ + Version="1.5.11.0" /> Telegram Desktop Telegram Messenger LLP diff -Nru telegram-desktop-1.5.8/Telegram/Resources/winrc/Telegram.rc telegram-desktop-1.5.11/Telegram/Resources/winrc/Telegram.rc --- telegram-desktop-1.5.8/Telegram/Resources/winrc/Telegram.rc 2019-01-21 17:28:45.000000000 +0000 +++ telegram-desktop-1.5.11/Telegram/Resources/winrc/Telegram.rc 2019-02-01 12:51:46.000000000 +0000 @@ -34,8 +34,8 @@ // VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,5,8,0 - PRODUCTVERSION 1,5,8,0 + FILEVERSION 1,5,11,0 + PRODUCTVERSION 1,5,11,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -52,10 +52,10 @@ BEGIN VALUE "CompanyName", "Telegram Messenger LLP" VALUE "FileDescription", "Telegram Desktop" - VALUE "FileVersion", "1.5.8.0" + VALUE "FileVersion", "1.5.11.0" VALUE "LegalCopyright", "Copyright (C) 2014-2019" VALUE "ProductName", "Telegram Desktop" - VALUE "ProductVersion", "1.5.8.0" + VALUE "ProductVersion", "1.5.11.0" END END BLOCK "VarFileInfo" diff -Nru telegram-desktop-1.5.8/Telegram/Resources/winrc/Updater.rc telegram-desktop-1.5.11/Telegram/Resources/winrc/Updater.rc --- telegram-desktop-1.5.8/Telegram/Resources/winrc/Updater.rc 2019-01-21 17:28:45.000000000 +0000 +++ telegram-desktop-1.5.11/Telegram/Resources/winrc/Updater.rc 2019-02-01 12:51:46.000000000 +0000 @@ -25,8 +25,8 @@ // VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,5,8,0 - PRODUCTVERSION 1,5,8,0 + FILEVERSION 1,5,11,0 + PRODUCTVERSION 1,5,11,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -43,10 +43,10 @@ BEGIN VALUE "CompanyName", "Telegram Messenger LLP" VALUE "FileDescription", "Telegram Desktop Updater" - VALUE "FileVersion", "1.5.8.0" + VALUE "FileVersion", "1.5.11.0" VALUE "LegalCopyright", "Copyright (C) 2014-2019" VALUE "ProductName", "Telegram Desktop" - VALUE "ProductVersion", "1.5.8.0" + VALUE "ProductVersion", "1.5.11.0" END END BLOCK "VarFileInfo" diff -Nru telegram-desktop-1.5.8/Telegram/SourceFiles/apiwrap.cpp telegram-desktop-1.5.11/Telegram/SourceFiles/apiwrap.cpp --- telegram-desktop-1.5.8/Telegram/SourceFiles/apiwrap.cpp 2019-01-21 17:28:45.000000000 +0000 +++ telegram-desktop-1.5.11/Telegram/SourceFiles/apiwrap.cpp 2019-02-01 12:51:46.000000000 +0000 @@ -22,12 +22,11 @@ #include "data/data_user.h" #include "dialogs/dialogs_key.h" #include "core/core_cloud_password.h" +#include "core/application.h" #include "base/openssl_help.h" #include "observer_peer.h" #include "lang/lang_keys.h" -#include "application.h" #include "mainwindow.h" -#include "messenger.h" #include "mainwidget.h" #include "boxes/add_contact_box.h" #include "history/history.h" @@ -266,12 +265,12 @@ proxy.match([&](const MTPDhelp_proxyDataEmpty &data) { _session->data().setProxyPromoted(nullptr); }, [&](const MTPDhelp_proxyDataPromo &data) { - App::feedChats(data.vchats); - App::feedUsers(data.vusers); + _session->data().processChats(data.vchats); + _session->data().processUsers(data.vusers); const auto peerId = peerFromMTP(data.vpeer); const auto peer = _session->data().peer(peerId); _session->data().setProxyPromoted(peer); - if (const auto history = App::historyLoaded(peer)) { + if (const auto history = _session->data().historyLoaded(peer)) { requestDialogEntry(history); } }); @@ -329,7 +328,7 @@ const auto &data = result.c_help_termsOfServiceUpdate(); const auto &terms = data.vterms_of_service; const auto &fields = terms.c_help_termsOfService(); - Messenger::Instance().lockByTerms( + Core::App().lockByTerms( Window::TermsLock::FromMTP(fields)); requestNext(data); } break; @@ -378,7 +377,7 @@ }, [](auto&&) { return PeerId(0); }); - if (const auto peer = App::peerLoaded(peerId)) { + if (const auto peer = _session->data().peerLoaded(peerId)) { App::wnd()->controller()->showPeerHistory( peer, Window::SectionShow::Way::Forward); @@ -478,7 +477,7 @@ PeerFloodErrorText(PeerFloodType::Send))); } else if (error.type() == qstr("USER_BANNED_IN_CHANNEL")) { const auto link = textcmdLink( - Messenger::Instance().createInternalLinkFull(qsl("spambot")), + Core::App().createInternalLinkFull(qsl("spambot")), lang(lng_cant_more_info)); Ui::show(Box(lng_error_public_groups_denied( lt_more_info, @@ -563,8 +562,8 @@ void ApiWrap::gotMessageDatas(ChannelData *channel, const MTPmessages_Messages &msgs, mtpRequestId requestId) { auto handleResult = [&](auto &&result) { - App::feedUsers(result.vusers); - App::feedChats(result.vchats); + _session->data().processUsers(result.vusers); + _session->data().processChats(result.vchats); App::feedMsgs(result.vmessages, NewMessageExisting); }; switch (msgs.type()) { @@ -624,7 +623,7 @@ } Assert(result.type() == mtpc_contacts_contacts); const auto &d = result.c_contacts_contacts(); - App::feedUsers(d.vusers); + _session->data().processUsers(d.vusers); for (const auto &contact : d.vcontacts.v) { if (contact.type() != mtpc_contact) continue; @@ -763,15 +762,15 @@ Expects(dialogs.type() == mtpc_messages_peerDialogs); const auto &data = dialogs.c_messages_peerDialogs(); - App::feedUsers(data.vusers); - App::feedChats(data.vchats); + _session->data().processUsers(data.vusers); + _session->data().processChats(data.vchats); App::feedMsgs(data.vmessages, NewMessageLast); for (const auto &dialog : data.vdialogs.v) { switch (dialog.type()) { case mtpc_dialog: { const auto &fields = dialog.c_dialog(); if (const auto peerId = peerFromMTP(fields.vpeer)) { - App::history(peerId)->applyDialog(fields); + _session->data().history(peerId)->applyDialog(fields); } } break; @@ -798,15 +797,15 @@ dialogs.match([&](const MTPDmessages_dialogsNotModified &) { Unexpected("Type in ApiWrap::applyFeedDialogs."); }, [&](const auto &data) { - App::feedUsers(data.vusers); - App::feedChats(data.vchats); + _session->data().processUsers(data.vusers); + _session->data().processChats(data.vchats); App::feedMsgs(data.vmessages.v, NewMessageLast); channels.reserve(data.vdialogs.v.size()); for (const auto &dialog : data.vdialogs.v) { dialog.match([&](const MTPDdialog &data) { if (const auto peerId = peerFromMTP(data.vpeer)) { if (peerIsChannel(peerId)) { - const auto history = App::history(peerId); + const auto history = _session->data().history(peerId); history->applyDialog(dialog.c_dialog()); channels.emplace_back(history->peer->asChannel()); } else { @@ -885,23 +884,13 @@ )).done([=](const MTPWallPaper &result) { _wallPaperRequestId = 0; _wallPaperSlug = QString(); - result.match([&](const MTPDwallPaper &data) { - const auto document = _session->data().document(data.vdocument); - if (document->checkWallPaperProperties()) { - if (const auto done = base::take(_wallPaperDone)) { - done({ - data.vid.v, - data.vaccess_hash.v, - data.vflags.v, - qs(data.vslug), - document->thumb, - document - }); - } - } else if (const auto fail = base::take(_wallPaperFail)) { - fail(RPCError::Local("BAD_DOCUMENT", "In a wallpaper.")); + if (const auto paper = Data::WallPaper::Create(result)) { + if (const auto done = base::take(_wallPaperDone)) { + done(*paper); } - }); + } else if (const auto fail = base::take(_wallPaperFail)) { + fail(RPCError::Local("BAD_DOCUMENT", "In a wallpaper.")); + } }).fail([=](const RPCError &error) { _wallPaperRequestId = 0; _wallPaperSlug = QString(); @@ -972,8 +961,8 @@ const auto &d = result.c_messages_chatFull(); _session->data().applyMaximumChatVersions(d.vchats); - App::feedUsers(d.vusers); - App::feedChats(d.vchats); + _session->data().processUsers(d.vusers); + _session->data().processChats(d.vchats); using UpdateFlag = Notify::PeerUpdate::Flag; if (const auto chat = peer->asChat()) { @@ -987,7 +976,7 @@ if (f.has_bot_info()) { for (const auto &item : f.vbot_info.v) { item.match([&](const MTPDbotInfo &data) { - if (const auto bot = App::userLoaded(data.vuser_id.v)) { + if (const auto bot = _session->data().userLoaded(data.vuser_id.v)) { bot->setBotInfo(item); fullPeerUpdated().notify(bot); } @@ -1029,7 +1018,7 @@ if (f.has_migrated_from_chat_id()) { channel->addFlags(MTPDchannel::Flag::f_megagroup); const auto chat = channel->owner().chat( - peerFromChat(f.vmigrated_from_chat_id)); + f.vmigrated_from_chat_id.v); Data::ApplyMigration(chat, channel); } for (const auto &item : f.vbot_info.v) { @@ -1047,7 +1036,7 @@ channel->setRestrictedCount(f.has_banned_count() ? f.vbanned_count.v : 0); channel->setKickedCount(f.has_kicked_count() ? f.vkicked_count.v : 0); channel->setInviteLink((f.vexported_invite.type() == mtpc_chatInviteExported) ? qs(f.vexported_invite.c_chatInviteExported().vlink) : QString()); - if (const auto history = App::historyLoaded(channel->id)) { + if (const auto history = _session->data().historyLoaded(channel)) { history->clearUpTill(f.vavailable_min_id.v); history->applyDialogFields( f.vunread_count.v, @@ -1108,9 +1097,9 @@ }); return; } - App::feedUsers(MTP_vector(1, d.vuser)); + _session->data().processUser(d.vuser); if (d.has_profile_photo()) { - _session->data().photo(d.vprofile_photo); + _session->data().processPhoto(d.vprofile_photo); } App::feedUserLink(MTP_int(peerToUser(user->id)), d.vlink.c_contacts_link().vmy_link, d.vlink.c_contacts_link().vforeign_link); if (App::main()) { @@ -1158,14 +1147,14 @@ return data.vchats; }); _session->data().applyMaximumChatVersions(chats); - App::feedChats(chats); + _session->data().processChats(chats); }; if (const auto user = peer->asUser()) { return request(MTPusers_GetUsers( MTP_vector(1, user->inputUser) )).done([=](const MTPVector &result) { _peerRequests.remove(user); - App::feedUsers(result); + _session->data().processUsers(result); }).fail(failHandler).send(); } else if (const auto chat = peer->asChat()) { return request(MTPmessages_GetChats( @@ -1352,7 +1341,7 @@ } } const auto handleChats = [=](const MTPmessages_Chats &result) { - App::feedChats(result.match([](const auto &data) { + _session->data().processChats(result.match([](const auto &data) { return data.vchats; })); }; @@ -1370,7 +1359,7 @@ request(MTPusers_GetUsers( MTP_vector(users) )).done([=](const MTPVector &result) { - App::feedUsers(result); + _session->data().processUsers(result); }).send(); } } @@ -1452,7 +1441,7 @@ )).done([this, channel](const MTPchannels_ChannelParticipants &result) { _adminsRequests.remove(channel); result.match([&](const MTPDchannels_channelParticipants &data) { - App::feedUsers(data.vusers); + _session->data().processUsers(data.vusers); applyAdminsList( channel, data.vcount.v, @@ -1498,7 +1487,7 @@ continue; } - auto user = App::user(userId); + auto user = _session->data().user(userId); if (p.type() == mtpc_channelParticipantCreator) { channel->mgInfo->creator = user; if (!channel->mgInfo->admins.empty() @@ -1550,7 +1539,7 @@ not_null channel, int availableCount, const QVector &list) { - const auto history = App::historyLoaded(channel->id); + const auto history = _session->data().historyLoaded(channel); channel->mgInfo->bots.clear(); channel->mgInfo->botStatus = -1; @@ -1565,7 +1554,7 @@ continue; } - auto user = App::user(userId); + auto user = _session->data().user(userId); if (user->botInfo) { channel->mgInfo->bots.insert(user); botStatus = 2;// (botStatus > 0/* || !i.key()->botInfo->readsAllHistory*/) ? 2 : 1; @@ -1629,7 +1618,7 @@ const auto finalize = [=](UserId inviter, TimeId inviteDate) { channel->inviter = inviter; channel->inviteDate = inviteDate; - if (const auto history = App::historyLoaded(channel)) { + if (const auto history = _session->data().historyLoaded(channel)) { if (history->lastMessageKnown()) { history->checkJoinedMessage(true); history->owner().sendHistoryChangeNotifications(); @@ -1645,7 +1634,7 @@ )).done([=](const MTPchannels_ChannelParticipant &result) { _selfParticipantRequests.erase(channel); result.match([&](const MTPDchannels_channelParticipant &data) { - App::feedUsers(data.vusers); + _session->data().processUsers(data.vusers); const auto &participant = data.vparticipant; participant.match([&](const MTPDchannelParticipantSelf &data) { @@ -1778,7 +1767,7 @@ void ApiWrap::deleteAllFromUser( not_null channel, not_null from) { - const auto history = App::historyLoaded(channel->id); + const auto history = _session->data().historyLoaded(channel); const auto ids = history ? history->collectMessagesFromUserToDelete(from) : QVector(); @@ -1804,7 +1793,7 @@ const auto offset = applyAffectedHistory(channel, result); if (offset > 0) { deleteAllFromUserSend(channel, from); - } else if (const auto history = App::historyLoaded(channel)) { + } else if (const auto history = _session->data().historyLoaded(channel)) { history->requestChatListMessage(); } }).send(); @@ -2196,7 +2185,7 @@ Expects(result.type() == mtpc_account_privacyRules); auto &rules = result.c_account_privacyRules(); - App::feedUsers(rules.vusers); + _session->data().processUsers(rules.vusers); _privacySaveRequests.remove(keyTypeId); handlePrivacyChange(keyTypeId, rules.vrules); }).fail([=](const RPCError &error) { @@ -2306,7 +2295,7 @@ for_const (auto &item, result.v) { Assert(item.type() == mtpc_contactStatus); auto &data = item.c_contactStatus(); - if (auto user = App::userLoaded(data.vuser_id.v)) { + if (auto user = _session->data().userLoaded(data.vuser_id.v)) { auto oldOnlineTill = user->onlineTill; auto newOnlineTill = OnlineTillFromStatus(data.vstatus, oldOnlineTill); if (oldOnlineTill != newOnlineTill) { @@ -2338,7 +2327,7 @@ void ApiWrap::clearHistory(not_null peer) { auto deleteTillId = MsgId(0); - if (const auto history = App::historyLoaded(peer->id)) { + if (const auto history = _session->data().historyLoaded(peer)) { if (const auto last = history->lastMessage()) { deleteTillId = last->id; } @@ -2487,7 +2476,7 @@ if (App::quitting()) { LOG(("ApiWrap doesn't prevent quit any more.")); } - Messenger::Instance().quitPreventFinished(); + Core::App().quitPreventFinished(); } } @@ -2704,8 +2693,8 @@ case mtpc_updates_channelDifferenceTooLong: { const auto &d = result.c_updates_channelDifferenceTooLong(); - App::feedUsers(d.vusers); - App::feedChats(d.vchats); + _session->data().processUsers(d.vusers); + _session->data().processChats(d.vchats); nextRequestPts = d.vpts.v; isFinal = d.is_final(); @@ -2829,7 +2818,7 @@ fail(); } }, [&](Data::FileOriginUserPhoto data) { - if (const auto user = App::user(data.userId)) { + if (const auto user = _session->data().user(data.userId)) { request(MTPphotos_GetUserPhotos( user->inputUser, MTP_int(-1), @@ -2839,7 +2828,7 @@ fail(); } }, [&](Data::FileOriginPeerPhoto data) { - if (const auto peer = App::peer(data.peerId)) { + if (const auto peer = _session->data().peer(data.peerId)) { if (const auto user = peer->asUser()) { request(MTPusers_GetUsers( MTP_vector(1, user->inputUser))); @@ -2895,15 +2884,15 @@ switch (msgs.type()) { case mtpc_messages_messages: { auto &d = msgs.c_messages_messages(); - App::feedUsers(d.vusers); - App::feedChats(d.vchats); + _session->data().processUsers(d.vusers); + _session->data().processChats(d.vchats); v = &d.vmessages.v; } break; case mtpc_messages_messagesSlice: { auto &d = msgs.c_messages_messagesSlice(); - App::feedUsers(d.vusers); - App::feedChats(d.vchats); + _session->data().processUsers(d.vusers); + _session->data().processChats(d.vchats); v = &d.vmessages.v; } break; @@ -2914,8 +2903,8 @@ } else { LOG(("API Error: received messages.channelMessages when no channel was passed! (ApiWrap::gotWebPages)")); } - App::feedUsers(d.vusers); - App::feedChats(d.vchats); + _session->data().processUsers(d.vusers); + _session->data().processChats(d.vchats); v = &d.vmessages.v; } break; @@ -3023,7 +3012,8 @@ entry.list.clear(); entry.list.reserve(data.vstickers.v.size()); for (const auto &sticker : data.vstickers.v) { - const auto document = _session->data().document(sticker); + const auto document = _session->data().processDocument( + sticker); if (document->sticker()) { entry.list.push_back(document); } @@ -3311,7 +3301,7 @@ const QVector &list)> callbackList, Fn callbackNotModified) { result.match([&](const MTPDchannels_channelParticipants &data) { - App::feedUsers(data.vusers); + _session->data().processUsers(data.vusers); if (channel->mgInfo) { refreshChannelAdmins(channel, data.vparticipants.v); } @@ -3557,14 +3547,13 @@ MTP_int(minId), MTP_int(historyHash) )).done([ - peer, - offsetDate, + =, callback = std::forward(callback) ](const MTPmessages_Messages &result) { - auto getMessagesList = [&result, peer]() -> const QVector* { - auto handleMessages = [](auto &messages) { - App::feedUsers(messages.vusers); - App::feedChats(messages.vchats); + auto getMessagesList = [&]() -> const QVector* { + auto handleMessages = [&](auto &messages) { + _session->data().processUsers(messages.vusers); + _session->data().processChats(messages.vchats); return &messages.vmessages.v; }; switch (result.type()) { @@ -3660,8 +3649,8 @@ // const auto &data = result.c_messages_feedMessages(); // const auto &messages = data.vmessages.v; // const auto type = NewMessageExisting; - // App::feedUsers(data.vusers); - // App::feedChats(data.vchats); + // _session->data().processUsers(data.vusers); + // _session->data().processChats(data.vchats); // for (const auto &msg : messages) { // if (const auto item = _session->data().addNewMessage(msg, type)) { // if (item->date() >= offsetDate || true) { @@ -3863,14 +3852,14 @@ switch (result.type()) { case mtpc_photos_photos: { auto &d = result.c_photos_photos(); - App::feedUsers(d.vusers); + _session->data().processUsers(d.vusers); fullCount = d.vphotos.v.size(); return &d.vphotos.v; } break; case mtpc_photos_photosSlice: { auto &d = result.c_photos_photosSlice(); - App::feedUsers(d.vusers); + _session->data().processUsers(d.vusers); fullCount = d.vcount.v; return &d.vphotos.v; } break; @@ -3881,7 +3870,7 @@ auto photoIds = std::vector(); photoIds.reserve(photos.size()); for (auto &photo : photos) { - if (auto photoData = _session->data().photo(photo)) { + if (auto photoData = _session->data().processPhoto(photo)) { photoIds.push_back(photoData->id); } } @@ -3943,14 +3932,14 @@ // const auto feed = _session->data().feed(feedId); // auto channels = std::vector>(); // for (const auto &channelId : list.vchannels.v) { -// channels.push_back(App::channel(channelId.v)); +// channels.push_back(_session->data().channel(channelId.v)); // } // feed->setChannels(std::move(channels)); // } // } // -// App::feedUsers(data.vusers); -// App::feedChats(data.vchats); +// _session->data().processUsers(data.vusers); +// _session->data().processChats(data.vchats); // // if (data.has_newly_joined_feed()) { // _session->data().setDefaultFeedId( @@ -4085,8 +4074,8 @@ // const auto tooSmallPosition = [&](const auto &position) { // return (slice == SliceType::After) && !(messageId < position); // }; -// App::feedUsers(data.vusers); -// App::feedChats(data.vchats); +// _session->data().processUsers(data.vusers); +// _session->data().processChats(data.vchats); // if (!messages.empty()) { // ids.reserve(messages.size()); // for (const auto &msg : messages) { @@ -4662,7 +4651,7 @@ auto &info = bot->botInfo; auto &token = chat ? info->startGroupToken : info->startToken; if (token.isEmpty()) { - auto message = ApiWrap::MessageToSend(App::history(bot)); + auto message = ApiWrap::MessageToSend(_session->data().history(bot)); message.textWithTags = { qsl("/start"), TextWithTags::Tags() }; sendMessage(std::move(message)); return; @@ -5135,18 +5124,18 @@ file )).done([=](const MTPphotos_Photo &result) { result.match([&](const MTPDphotos_photo &data) { - _session->data().photo(data.vphoto); - App::feedUsers(data.vusers); + _session->data().processPhoto(data.vphoto); + _session->data().processUsers(data.vusers); }); }).send(); } else if (const auto chat = peer->asChat()) { - const auto history = App::history(chat); + const auto history = _session->data().history(chat); history->sendRequestId = request(MTPmessages_EditChatPhoto( chat->inputChat, MTP_inputChatUploadedPhoto(file) )).done(applier).afterRequest(history->sendRequestId).send(); } else if (const auto channel = peer->asChannel()) { - const auto history = App::history(channel); + const auto history = _session->data().history(channel); history->sendRequestId = request(MTPchannels_EditPhoto( channel->inputChannel, MTP_inputChatUploadedPhoto(file) @@ -5298,7 +5287,7 @@ )).done([=](const MTPUser &result) { _saveBioRequestId = 0; - App::feedUsers(MTP_vector(1, result)); + _session->data().processUsers(MTP_vector(1, result)); _session->user()->setAbout(_saveBioText); if (_saveBioDone) { _saveBioDone(); @@ -5317,7 +5306,7 @@ )).done([=](const MTPaccount_PrivacyRules &result) { _privacyRequestIds.erase(key); result.match([&](const MTPDaccount_privacyRules &data) { - App::feedUsers(data.vusers); + _session->data().processUsers(data.vusers); pushPrivacy(key, data.vrules.v); }); }).fail([=](const RPCError &error) { @@ -5351,7 +5340,7 @@ const auto &users = data.vusers.v; always.reserve(always.size() + users.size()); for (const auto userId : users) { - const auto user = App::user(UserId(userId.v)); + const auto user = _session->data().user(UserId(userId.v)); if (!base::contains(never, user) && !base::contains(always, user)) { always.push_back(user); @@ -5365,7 +5354,7 @@ const auto &users = data.vusers.v; never.reserve(never.size() + users.size()); for (const auto userId : users) { - const auto user = App::user(UserId(userId.v)); + const auto user = _session->data().user(UserId(userId.v)); if (!base::contains(always, user) && !base::contains(never, user)) { never.push_back(user); @@ -5589,7 +5578,7 @@ if (!channel->amIn()) { return; // no read request for channels that I didn't join } else if (const auto migrateFrom = channel->migrateFrom()) { - if (const auto migrated = App::historyLoaded(migrateFrom)) { + if (const auto migrated = _session->data().historyLoaded(migrateFrom)) { readServerHistory(migrated); } } diff -Nru telegram-desktop-1.5.8/Telegram/SourceFiles/apiwrap.h telegram-desktop-1.5.11/Telegram/SourceFiles/apiwrap.h --- telegram-desktop-1.5.8/Telegram/SourceFiles/apiwrap.h 2019-01-21 17:28:45.000000000 +0000 +++ telegram-desktop-1.5.11/Telegram/SourceFiles/apiwrap.h 2019-02-01 12:51:46.000000000 +0000 @@ -25,7 +25,7 @@ namespace Data { struct UpdatedFileReferences; -struct WallPaper; +class WallPaper; } // namespace Data namespace InlineBots { diff -Nru telegram-desktop-1.5.8/Telegram/SourceFiles/app.cpp telegram-desktop-1.5.11/Telegram/SourceFiles/app.cpp --- telegram-desktop-1.5.8/Telegram/SourceFiles/app.cpp 2019-01-21 17:28:45.000000000 +0000 +++ telegram-desktop-1.5.11/Telegram/SourceFiles/app.cpp 2019-02-01 12:51:46.000000000 +0000 @@ -7,11 +7,6 @@ */ #include "app.h" -#include "styles/style_overview.h" -#include "styles/style_mediaview.h" -#include "styles/style_chat_helpers.h" -#include "styles/style_history.h" -#include "styles/style_boxes.h" #include "lang/lang_keys.h" #include "boxes/confirm_box.h" #include "data/data_channel.h" @@ -30,6 +25,8 @@ #include "inline_bots/inline_bot_layout_item.h" #include "core/crash_reports.h" #include "core/update_checker.h" +#include "core/sandbox.h" +#include "core/application.h" #include "window/themes/window_theme.h" #include "window/notifications_manager.h" #include "platform/platform_notifications_manager.h" @@ -37,14 +34,17 @@ #include "storage/localstorage.h" #include "storage/storage_facade.h" #include "storage/storage_shared_media.h" -#include "messenger.h" -#include "application.h" #include "mainwindow.h" #include "mainwidget.h" #include "apiwrap.h" #include "numbers.h" #include "observer_peer.h" #include "auth_session.h" +#include "styles/style_overview.h" +#include "styles/style_mediaview.h" +#include "styles/style_chat_helpers.h" +#include "styles/style_history.h" +#include "styles/style_boxes.h" #ifdef OS_MAC_OLD #include @@ -117,8 +117,8 @@ } MainWindow *wnd() { - if (auto instance = Messenger::InstancePointer()) { - return instance->getActiveWindow(); + if (Core::Sandbox::Instance().applicationLaunched()) { + return Core::App().getActiveWindow(); } return nullptr; } @@ -130,22 +130,6 @@ return nullptr; } - UserData *feedUser(const MTPUser &user) { - return Auth().data().user(user); - } - - UserData *feedUsers(const MTPVector &users) { - return Auth().data().processUsers(users); - } - - PeerData *feedChat(const MTPChat &chat) { - return Auth().data().chat(chat); - } - - PeerData *feedChats(const MTPVector &chats) { - return Auth().data().processChats(chats); - } - bool checkEntitiesAndViewsUpdate(const MTPDmessage &m) { auto peerId = peerFromMTP(m.vto_id); if (m.has_from_id() && peerId == Auth().userPeerId()) { @@ -337,13 +321,13 @@ } void feedInboxRead(const PeerId &peer, MsgId upTo) { - if (const auto history = App::historyLoaded(peer)) { + if (const auto history = Auth().data().historyLoaded(peer)) { history->inboxRead(upTo); } } void feedOutboxRead(const PeerId &peer, MsgId upTo, TimeId when) { - if (auto history = App::historyLoaded(peer)) { + if (auto history = Auth().data().historyLoaded(peer)) { history->outboxRead(upTo); if (const auto user = history->peer->asUser()) { user->madeAction(when); @@ -371,7 +355,7 @@ if (!data) return; const auto affectedHistory = (channelId != NoChannel) - ? App::history(peerFromChannel(channelId)).get() + ? Auth().data().history(peerFromChannel(channelId)).get() : nullptr; auto historiesToCheck = base::flat_set>(); @@ -393,7 +377,7 @@ } void feedUserLink(MTPint userId, const MTPContactLink &myLink, const MTPContactLink &foreignLink) { - if (const auto user = userLoaded(userId.v)) { + if (const auto user = Auth().data().userLoaded(userId.v)) { const auto wasShowPhone = (user->contactStatus() == UserData::ContactStatus::CanAdd); switch (myLink.type()) { case mtpc_contactLinkContact: @@ -431,51 +415,10 @@ } } - not_null peer(PeerId id) { - return Auth().data().peer(id); - } - not_null user(UserId id) { - return Auth().data().user(id); - } - not_null chat(ChatId id) { - return Auth().data().chat(id); - } - not_null channel(ChannelId id) { - return Auth().data().channel(id); - } - PeerData *peerLoaded(PeerId id) { - return Auth().data().peerLoaded(id); - } - UserData *userLoaded(UserId id) { - return Auth().data().userLoaded(id); - } - ChatData *chatLoaded(ChatId id) { - return Auth().data().chatLoaded(id); - } - ChannelData *channelLoaded(ChannelId id) { - return Auth().data().channelLoaded(id); - } - QString peerName(const PeerData *peer, bool forDialogs) { return peer ? ((forDialogs && peer->isUser() && !peer->asUser()->nameOrPhone.isEmpty()) ? peer->asUser()->nameOrPhone : peer->name) : lang(lng_deleted); } - not_null history(PeerId peer) { - return Auth().data().history(peer); - } - - History *historyLoaded(PeerId peer) { - return Auth().data().historyLoaded(peer); - } - - not_null history(not_null peer) { - return history(peer->id); - } - - History *historyLoaded(const PeerData *peer) { - return peer ? historyLoaded(peer->id) : nullptr; - } - HistoryItem *histItemById(ChannelId channelId, MsgId itemId) { if (!itemId) return nullptr; @@ -810,14 +753,14 @@ setLaunchState(QuitRequested); if (auto window = App::wnd()) { - if (!Core::App().isSavingSession()) { + if (!Core::Sandbox::Instance().isSavingSession()) { window->hide(); } } if (auto mainwidget = App::main()) { mainwidget->saveDraftToCloud(); } - Messenger::QuitAttempt(); + Core::Application::QuitAttempt(); } bool quitting() { diff -Nru telegram-desktop-1.5.8/Telegram/SourceFiles/app.h telegram-desktop-1.5.11/Telegram/SourceFiles/app.h --- telegram-desktop-1.5.8/Telegram/SourceFiles/app.h 2019-01-21 17:28:45.000000000 +0000 +++ telegram-desktop-1.5.11/Telegram/SourceFiles/app.h 2019-02-01 12:51:46.000000000 +0000 @@ -11,7 +11,6 @@ enum NewMessageType : char; enum class ImageRoundRadius; -class Messenger; class MainWindow; class MainWidget; class HistoryItem; @@ -65,11 +64,6 @@ QString formatPhone(QString phone); - UserData *feedUser(const MTPUser &user); - UserData *feedUsers(const MTPVector &users); // returns last user - PeerData *feedChat(const MTPChat &chat); - PeerData *feedChats(const MTPVector &chats); // returns last chat - bool checkEntitiesAndViewsUpdate(const MTPDmessage &m); // returns true if item found and it is not detached void updateEditedMessage(const MTPMessage &m); void addSavedGif(DocumentData *doc); @@ -83,22 +77,9 @@ ImagePtr image(const MTPPhotoSize &size); - [[nodiscard]] not_null peer(PeerId id); - [[nodiscard]] not_null user(UserId userId); - [[nodiscard]] not_null chat(ChatId chatId); - [[nodiscard]] not_null channel(ChannelId channelId); - [[nodiscard]] PeerData *peerLoaded(PeerId id); - [[nodiscard]] UserData *userLoaded(UserId userId); - [[nodiscard]] ChatData *chatLoaded(ChatId chatId); - [[nodiscard]] ChannelData *channelLoaded(ChannelId channelId); - [[nodiscard]] QString peerName(const PeerData *peer, bool forDialogs = false); - [[nodiscard]] not_null history(PeerId peer); - [[nodiscard]] History *historyLoaded(PeerId peer); [[nodiscard]] HistoryItem *histItemById(ChannelId channelId, MsgId itemId); - [[nodiscard]] not_null history(not_null peer); - [[nodiscard]] History *historyLoaded(const PeerData *peer); [[nodiscard]] HistoryItem *histItemById( const ChannelData *channel, MsgId itemId); diff -Nru telegram-desktop-1.5.8/Telegram/SourceFiles/application.cpp telegram-desktop-1.5.11/Telegram/SourceFiles/application.cpp --- telegram-desktop-1.5.8/Telegram/SourceFiles/application.cpp 2019-01-21 17:28:45.000000000 +0000 +++ telegram-desktop-1.5.11/Telegram/SourceFiles/application.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,560 +0,0 @@ -/* -This file is part of Telegram Desktop, -the official desktop application for the Telegram messaging service. - -For license and copyright information please follow this link: -https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL -*/ -#include "application.h" - -#include "platform/platform_specific.h" -#include "mainwidget.h" -#include "mainwindow.h" -#include "storage/localstorage.h" -#include "window/notifications_manager.h" -#include "core/crash_reports.h" -#include "messenger.h" -#include "base/timer.h" -#include "base/concurrent_timer.h" -#include "base/qthelp_url.h" -#include "base/qthelp_regex.h" -#include "core/update_checker.h" -#include "core/crash_report_window.h" - -namespace { - -constexpr auto kEmptyPidForCommandResponse = 0ULL; - -QChar _toHex(ushort v) { - v = v & 0x000F; - return QChar::fromLatin1((v >= 10) ? ('a' + (v - 10)) : ('0' + v)); -} -ushort _fromHex(QChar c) { - return ((c.unicode() >= uchar('a')) ? (c.unicode() - uchar('a') + 10) : (c.unicode() - uchar('0'))) & 0x000F; -} - -QString _escapeTo7bit(const QString &str) { - QString result; - result.reserve(str.size() * 2); - for (int i = 0, l = str.size(); i != l; ++i) { - QChar ch(str.at(i)); - ushort uch(ch.unicode()); - if (uch < 32 || uch > 127 || uch == ushort(uchar('%'))) { - result.append('%').append(_toHex(uch >> 12)).append(_toHex(uch >> 8)).append(_toHex(uch >> 4)).append(_toHex(uch)); - } else { - result.append(ch); - } - } - return result; -} - -QString _escapeFrom7bit(const QString &str) { - QString result; - result.reserve(str.size()); - for (int i = 0, l = str.size(); i != l; ++i) { - QChar ch(str.at(i)); - if (ch == QChar::fromLatin1('%') && i + 4 < l) { - result.append(QChar(ushort((_fromHex(str.at(i + 1)) << 12) | (_fromHex(str.at(i + 2)) << 8) | (_fromHex(str.at(i + 3)) << 4) | _fromHex(str.at(i + 4))))); - i += 4; - } else { - result.append(ch); - } - } - return result; -} - -} // namespace - -bool InternalPassportLink(const QString &url) { - const auto urlTrimmed = url.trimmed(); - if (!urlTrimmed.startsWith(qstr("tg://"), Qt::CaseInsensitive)) { - return false; - } - const auto command = urlTrimmed.midRef(qstr("tg://").size()); - - using namespace qthelp; - const auto matchOptions = RegExOption::CaseInsensitive; - const auto authMatch = regex_match( - qsl("^passport/?\\?(.+)(#|$)"), - command, - matchOptions); - const auto usernameMatch = regex_match( - qsl("^resolve/?\\?(.+)(#|$)"), - command, - matchOptions); - const auto usernameValue = usernameMatch->hasMatch() - ? url_parse_params( - usernameMatch->captured(1), - UrlParamNameTransform::ToLower).value(qsl("domain")) - : QString(); - const auto authLegacy = (usernameValue == qstr("telegrampassport")); - return authMatch->hasMatch() || authLegacy; -} - -bool StartUrlRequiresActivate(const QString &url) { - return Messenger::Instance().locked() - ? true - : !InternalPassportLink(url); -} - -Application::Application( - not_null launcher, - int &argc, - char **argv) -: QApplication(argc, argv) -, _mainThreadId(QThread::currentThreadId()) -, _launcher(launcher) { -} - -int Application::execute() { - if (!Core::UpdaterDisabled()) { - _updateChecker = std::make_unique(); - } - const auto d = QFile::encodeName(QDir(cWorkingDir()).absolutePath()); - char h[33] = { 0 }; - hashMd5Hex(d.constData(), d.size(), h); -#ifndef OS_MAC_STORE - _localServerName = psServerPrefix() + h + '-' + cGUIDStr(); -#else // OS_MAC_STORE - h[4] = 0; // use only first 4 chars - _localServerName = psServerPrefix() + h; -#endif // OS_MAC_STORE - - connect(&_localSocket, SIGNAL(connected()), this, SLOT(socketConnected())); - connect(&_localSocket, SIGNAL(disconnected()), this, SLOT(socketDisconnected())); - connect(&_localSocket, SIGNAL(error(QLocalSocket::LocalSocketError)), this, SLOT(socketError(QLocalSocket::LocalSocketError))); - connect(&_localSocket, SIGNAL(bytesWritten(qint64)), this, SLOT(socketWritten(qint64))); - connect(&_localSocket, SIGNAL(readyRead()), this, SLOT(socketReading())); - connect(&_localServer, SIGNAL(newConnection()), this, SLOT(newInstanceConnected())); - - QTimer::singleShot(0, this, SLOT(startApplication())); - connect(this, SIGNAL(aboutToQuit()), this, SLOT(closeApplication())); - - if (cManyInstance()) { - LOG(("Many instance allowed, starting...")); - singleInstanceChecked(); - } else { - LOG(("Connecting local socket to %1...").arg(_localServerName)); - _localSocket.connectToServer(_localServerName); - } - - return exec(); -} - -Application::~Application() = default; - -bool Application::event(QEvent *e) { - if (e->type() == QEvent::Close) { - App::quit(); - } - return QApplication::event(e); -} - -void Application::socketConnected() { - LOG(("Socket connected, this is not the first application instance, sending show command...")); - _secondInstance = true; - - QString commands; - const QStringList &lst(cSendPaths()); - for (QStringList::const_iterator i = lst.cbegin(), e = lst.cend(); i != e; ++i) { - commands += qsl("SEND:") + _escapeTo7bit(*i) + ';'; - } - if (!cStartUrl().isEmpty()) { - commands += qsl("OPEN:") + _escapeTo7bit(cStartUrl()) + ';'; - } else { - commands += qsl("CMD:show;"); - } - - DEBUG_LOG(("Application Info: writing commands %1").arg(commands)); - _localSocket.write(commands.toLatin1()); -} - -void Application::socketWritten(qint64/* bytes*/) { - if (_localSocket.state() != QLocalSocket::ConnectedState) { - LOG(("Socket is not connected %1").arg(_localSocket.state())); - return; - } - if (_localSocket.bytesToWrite()) { - return; - } - LOG(("Show command written, waiting response...")); -} - -void Application::socketReading() { - if (_localSocket.state() != QLocalSocket::ConnectedState) { - LOG(("Socket is not connected %1").arg(_localSocket.state())); - return; - } - _localSocketReadData.append(_localSocket.readAll()); - if (QRegularExpression("RES:(\\d+);").match(_localSocketReadData).hasMatch()) { - uint64 pid = _localSocketReadData.mid(4, _localSocketReadData.length() - 5).toULongLong(); - if (pid != kEmptyPidForCommandResponse) { - psActivateProcess(pid); - } - LOG(("Show command response received, pid = %1, activating and quitting...").arg(pid)); - return App::quit(); - } -} - -void Application::socketError(QLocalSocket::LocalSocketError e) { - if (App::quitting()) return; - - if (_secondInstance) { - LOG(("Could not write show command, error %1, quitting...").arg(e)); - return App::quit(); - } - - if (e == QLocalSocket::ServerNotFoundError) { - LOG(("This is the only instance of Telegram, starting server and app...")); - } else { - LOG(("Socket connect error %1, starting server and app...").arg(e)); - } - _localSocket.close(); - -// Local server does not work in WinRT build. -#ifndef Q_OS_WINRT - psCheckLocalSocket(_localServerName); - - if (!_localServer.listen(_localServerName)) { - LOG(("Failed to start listening to %1 server, error %2").arg(_localServerName).arg(int(_localServer.serverError()))); - return App::quit(); - } -#endif // !Q_OS_WINRT - - if (!Core::UpdaterDisabled() - && !cNoStartUpdate() - && Core::checkReadyUpdate()) { - cSetRestartingUpdate(true); - DEBUG_LOG(("Application Info: installing update instead of starting app...")); - return App::quit(); - } - - singleInstanceChecked(); -} - -void Application::singleInstanceChecked() { - if (cManyInstance()) { - Logs::multipleInstances(); - } - - Sandbox::start(); - refreshGlobalProxy(); - - if (!Logs::started() || (!cManyInstance() && !Logs::instanceChecked())) { - new NotStartedWindow(); - } else { - const auto status = CrashReports::Start(); - if (status == CrashReports::CantOpen) { - new NotStartedWindow(); - } else if (status == CrashReports::LastCrashed) { - if (Sandbox::LastCrashDump().isEmpty()) { // don't handle bad closing for now - if (CrashReports::Restart() == CrashReports::CantOpen) { - new NotStartedWindow(); - } else { - Sandbox::launch(); - } - } else { - new LastCrashedWindow(); - } - } else { - Sandbox::launch(); - } - } -} - -void Application::socketDisconnected() { - if (_secondInstance) { - DEBUG_LOG(("Application Error: socket disconnected before command response received, quitting...")); - return App::quit(); - } -} - -void Application::newInstanceConnected() { - DEBUG_LOG(("Application Info: new local socket connected")); - for (QLocalSocket *client = _localServer.nextPendingConnection(); client; client = _localServer.nextPendingConnection()) { - _localClients.push_back(LocalClient(client, QByteArray())); - connect(client, SIGNAL(readyRead()), this, SLOT(readClients())); - connect(client, SIGNAL(disconnected()), this, SLOT(removeClients())); - } -} - -void Application::readClients() { - // This method can be called before Messenger is constructed. - QString startUrl; - QStringList toSend; - for (LocalClients::iterator i = _localClients.begin(), e = _localClients.end(); i != e; ++i) { - i->second.append(i->first->readAll()); - if (i->second.size()) { - QString cmds(QString::fromLatin1(i->second)); - int32 from = 0, l = cmds.length(); - for (int32 to = cmds.indexOf(QChar(';'), from); to >= from; to = (from < l) ? cmds.indexOf(QChar(';'), from) : -1) { - QStringRef cmd(&cmds, from, to - from); - if (cmd.startsWith(qsl("CMD:"))) { - Sandbox::execExternal(cmds.mid(from + 4, to - from - 4)); - const auto response = qsl("RES:%1;").arg(QCoreApplication::applicationPid()).toLatin1(); - i->first->write(response.data(), response.size()); - } else if (cmd.startsWith(qsl("SEND:"))) { - if (cSendPaths().isEmpty()) { - toSend.append(_escapeFrom7bit(cmds.mid(from + 5, to - from - 5))); - } - } else if (cmd.startsWith(qsl("OPEN:"))) { - auto activateRequired = true; - if (cStartUrl().isEmpty()) { - startUrl = _escapeFrom7bit(cmds.mid(from + 5, to - from - 5)).mid(0, 8192); - activateRequired = StartUrlRequiresActivate(startUrl); - } - if (activateRequired) { - Sandbox::execExternal("show"); - } - const auto responsePid = activateRequired - ? QCoreApplication::applicationPid() - : kEmptyPidForCommandResponse; - const auto response = qsl("RES:%1;").arg(responsePid).toLatin1(); - i->first->write(response.data(), response.size()); - } else { - LOG(("Application Error: unknown command %1 passed in local socket").arg(QString(cmd.constData(), cmd.length()))); - } - from = to + 1; - } - if (from > 0) { - i->second = i->second.mid(from); - } - } - } - if (!toSend.isEmpty()) { - QStringList paths(cSendPaths()); - paths.append(toSend); - cSetSendPaths(paths); - } - if (!cSendPaths().isEmpty()) { - if (App::wnd()) { - App::wnd()->sendPaths(); - } - } - if (!startUrl.isEmpty()) { - cSetStartUrl(startUrl); - } - if (auto messenger = Messenger::InstancePointer()) { - messenger->checkStartUrl(); - } -} - -void Application::removeClients() { - DEBUG_LOG(("Application Info: remove clients slot called, clients %1").arg(_localClients.size())); - for (LocalClients::iterator i = _localClients.begin(), e = _localClients.end(); i != e;) { - if (i->first->state() != QLocalSocket::ConnectedState) { - DEBUG_LOG(("Application Info: removing client")); - i = _localClients.erase(i); - e = _localClients.end(); - } else { - ++i; - } - } -} - -void Application::startApplication() { - if (App::quitting()) { - quit(); - } -} - -void Application::createMessenger() { - Expects(!App::quitting()); - - _messengerInstance = std::make_unique(_launcher); - - // Ideally this should go to constructor. - // But we want to catch all native events and Messenger installs - // its own filter that can filter out some of them. So we install - // our filter after the Messenger constructor installs his. - installNativeEventFilter(this); -} - -void Application::refreshGlobalProxy() { -#ifndef TDESKTOP_DISABLE_NETWORK_PROXY - const auto proxy = [&] { - if (Global::started()) { - return (Global::ProxySettings() == ProxyData::Settings::Enabled) - ? Global::SelectedProxy() - : ProxyData(); - } - return Sandbox::PreLaunchProxy(); - }(); - if (proxy.type == ProxyData::Type::Socks5 - || proxy.type == ProxyData::Type::Http) { - QNetworkProxy::setApplicationProxy( - ToNetworkProxy(ToDirectIpProxy(proxy))); - } else if (!Global::started() - || Global::ProxySettings() == ProxyData::Settings::System) { - QNetworkProxyFactory::setUseSystemConfiguration(true); - } else { - QNetworkProxy::setApplicationProxy(QNetworkProxy::NoProxy); - } -#endif // TDESKTOP_DISABLE_NETWORK_PROXY -} - -void Application::postponeCall(FnMut &&callable) { - Expects(callable != nullptr); - Expects(_eventNestingLevel >= _loopNestingLevel); - - // _loopNestingLevel == _eventNestingLevel means that we had a - // native event in a nesting loop that didn't get a notify() call - // after. That means we already have exited the nesting loop and - // there must not be any postponed calls with that nesting level. - if (_loopNestingLevel == _eventNestingLevel) { - Assert(_postponedCalls.empty() - || _postponedCalls.back().loopNestingLevel < _loopNestingLevel); - Assert(!_previousLoopNestingLevels.empty()); - - _loopNestingLevel = _previousLoopNestingLevels.back(); - _previousLoopNestingLevels.pop_back(); - } - - _postponedCalls.push_back({ - _loopNestingLevel, - std::move(callable) - }); -} - -void Application::incrementEventNestingLevel() { - ++_eventNestingLevel; -} - -void Application::decrementEventNestingLevel() { - if (_eventNestingLevel == _loopNestingLevel) { - _loopNestingLevel = _previousLoopNestingLevels.back(); - _previousLoopNestingLevels.pop_back(); - } - const auto processTillLevel = _eventNestingLevel - 1; - processPostponedCalls(processTillLevel); - _eventNestingLevel = processTillLevel; -} - -void Application::registerEnterFromEventLoop() { - if (_eventNestingLevel > _loopNestingLevel) { - _previousLoopNestingLevels.push_back(_loopNestingLevel); - _loopNestingLevel = _eventNestingLevel; - } -} - -bool Application::notify(QObject *receiver, QEvent *e) { - if (QThread::currentThreadId() != _mainThreadId) { - return QApplication::notify(receiver, e); - } - - const auto wrap = createEventNestingLevel(); - return QApplication::notify(receiver, e); -} - -void Application::processPostponedCalls(int level) { - while (!_postponedCalls.empty()) { - auto &last = _postponedCalls.back(); - if (last.loopNestingLevel != level) { - break; - } - auto taken = std::move(last); - _postponedCalls.pop_back(); - taken.callable(); - } -} - -bool Application::nativeEventFilter( - const QByteArray &eventType, - void *message, - long *result) { - registerEnterFromEventLoop(); - return false; -} - -void Application::activateWindowDelayed(not_null widget) { - if (_delayedActivationsPaused) { - return; - } else if (std::exchange(_windowForDelayedActivation, widget.get())) { - return; - } - crl::on_main(this, [=] { - if (const auto widget = base::take(_windowForDelayedActivation)) { - if (!widget->isHidden()) { - widget->activateWindow(); - } - } - }); -} - -void Application::pauseDelayedWindowActivations() { - _windowForDelayedActivation = nullptr; - _delayedActivationsPaused = true; -} - -void Application::resumeDelayedWindowActivations() { - _delayedActivationsPaused = false; -} - -void Application::closeApplication() { - if (App::launchState() == App::QuitProcessed) return; - App::setLaunchState(App::QuitProcessed); - - _messengerInstance.reset(); - - Sandbox::finish(); - - _localServer.close(); - for (LocalClients::iterator i = _localClients.begin(), e = _localClients.end(); i != e; ++i) { - disconnect(i->first, SIGNAL(disconnected()), this, SLOT(removeClients())); - i->first->close(); - } - _localClients.clear(); - - _localSocket.close(); - - _updateChecker = nullptr; -} - -namespace Sandbox { - -void execExternal(const QString &cmd) { - DEBUG_LOG(("Application Info: executing external command '%1'").arg(cmd)); - if (cmd == "show") { - if (App::wnd()) { - App::wnd()->activate(); - } else if (PreLaunchWindow::instance()) { - PreLaunchWindow::instance()->activate(); - } - } -} - -void launch() { - const auto dpi = Application::primaryScreen()->logicalDotsPerInch(); - LOG(("Primary screen DPI: %1").arg(dpi)); - if (dpi <= 108) { - cSetScreenScale(100); // 100%: 96 DPI (0-108) - } else if (dpi <= 132) { - cSetScreenScale(125); // 125%: 120 DPI (108-132) - } else if (dpi <= 168) { - cSetScreenScale(150); // 150%: 144 DPI (132-168) - } else if (dpi <= 216) { - cSetScreenScale(200); // 200%: 192 DPI (168-216) - } else if (dpi <= 264) { - cSetScreenScale(250); // 250%: 240 DPI (216-264) - } else { - cSetScreenScale(300); // 300%: 288 DPI (264-inf) - } - - auto devicePixelRatio = Core::App().devicePixelRatio(); - if (devicePixelRatio > 1.) { - if ((cPlatform() != dbipMac && cPlatform() != dbipMacOld) || (devicePixelRatio != 2.)) { - LOG(("Found non-trivial Device Pixel Ratio: %1").arg(devicePixelRatio)); - LOG(("Environmental variables: QT_DEVICE_PIXEL_RATIO='%1'").arg(QString::fromLatin1(qgetenv("QT_DEVICE_PIXEL_RATIO")))); - LOG(("Environmental variables: QT_SCALE_FACTOR='%1'").arg(QString::fromLatin1(qgetenv("QT_SCALE_FACTOR")))); - LOG(("Environmental variables: QT_AUTO_SCREEN_SCALE_FACTOR='%1'").arg(QString::fromLatin1(qgetenv("QT_AUTO_SCREEN_SCALE_FACTOR")))); - LOG(("Environmental variables: QT_SCREEN_SCALE_FACTORS='%1'").arg(QString::fromLatin1(qgetenv("QT_SCREEN_SCALE_FACTORS")))); - } - cSetRetinaFactor(devicePixelRatio); - cSetIntRetinaFactor(int32(cRetinaFactor())); - cSetScreenScale(kInterfaceScaleDefault); - } - - Core::App().createMessenger(); -} - -} // namespace Sandbox diff -Nru telegram-desktop-1.5.8/Telegram/SourceFiles/application.h telegram-desktop-1.5.11/Telegram/SourceFiles/application.h --- telegram-desktop-1.5.8/Telegram/SourceFiles/application.h 2019-01-21 17:28:45.000000000 +0000 +++ telegram-desktop-1.5.11/Telegram/SourceFiles/application.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,118 +0,0 @@ -/* -This file is part of Telegram Desktop, -the official desktop application for the Telegram messaging service. - -For license and copyright information please follow this link: -https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL -*/ -#pragma once - -namespace Core { -class Launcher; -class UpdateChecker; -} // namespace Core - -bool InternalPassportLink(const QString &url); -bool StartUrlRequiresActivate(const QString &url); - -class Application : public QApplication, private QAbstractNativeEventFilter { - Q_OBJECT - -public: - Application(not_null launcher, int &argc, char **argv); - - int execute(); - - void createMessenger(); - void refreshGlobalProxy(); - - void postponeCall(FnMut &&callable); - bool notify(QObject *receiver, QEvent *e) override; - void registerEnterFromEventLoop(); - auto createEventNestingLevel() { - incrementEventNestingLevel(); - return gsl::finally([=] { decrementEventNestingLevel(); }); - } - - void activateWindowDelayed(not_null widget); - void pauseDelayedWindowActivations(); - void resumeDelayedWindowActivations(); - - ~Application(); - -// Single instance application -public slots: - void socketConnected(); - void socketError(QLocalSocket::LocalSocketError e); - void socketDisconnected(); - void socketWritten(qint64 bytes); - void socketReading(); - void newInstanceConnected(); - - void readClients(); - void removeClients(); - - void startApplication(); // will be done in exec() - void closeApplication(); // will be done in aboutToQuit() - -protected: - bool event(QEvent *e) override; - -private: - typedef QPair LocalClient; - typedef QList LocalClients; - - struct PostponedCall { - int loopNestingLevel = 0; - FnMut callable; - }; - - void incrementEventNestingLevel(); - void decrementEventNestingLevel(); - bool nativeEventFilter( - const QByteArray &eventType, - void *message, - long *result) override; - void processPostponedCalls(int level); - - const Qt::HANDLE _mainThreadId = nullptr; - int _eventNestingLevel = 0; - int _loopNestingLevel = 0; - std::vector _previousLoopNestingLevels; - std::vector _postponedCalls; - - QPointer _windowForDelayedActivation; - bool _delayedActivationsPaused = false; - - not_null _launcher; - std::unique_ptr _messengerInstance; - - QString _localServerName, _localSocketReadData; - QLocalServer _localServer; - QLocalSocket _localSocket; - LocalClients _localClients; - bool _secondInstance = false; - - void singleInstanceChecked(); - -private: - std::unique_ptr _updateChecker; - -}; - -namespace Core { - -inline Application &App() { - Expects(QCoreApplication::instance() != nullptr); - - return *static_cast(QCoreApplication::instance()); -} - -} // namespace Core - -namespace Sandbox { - -void execExternal(const QString &cmd); -void launch(); - -} // namespace Sandbox diff -Nru telegram-desktop-1.5.8/Telegram/SourceFiles/auth_session.cpp telegram-desktop-1.5.11/Telegram/SourceFiles/auth_session.cpp --- telegram-desktop-1.5.8/Telegram/SourceFiles/auth_session.cpp 2019-01-21 17:28:45.000000000 +0000 +++ telegram-desktop-1.5.11/Telegram/SourceFiles/auth_session.cpp 2019-02-01 12:51:46.000000000 +0000 @@ -8,7 +8,8 @@ #include "auth_session.h" #include "apiwrap.h" -#include "messenger.h" +#include "core/application.h" +#include "core/sandbox.h" #include "core/changelogs.h" #include "storage/file_download.h" #include "storage/file_upload.h" @@ -372,7 +373,7 @@ } AuthSession &Auth() { - auto result = Messenger::Instance().authSession(); + auto result = Core::App().authSession(); Assert(result != nullptr); return *result; } @@ -386,17 +387,17 @@ , _storage(std::make_unique()) , _notifications(std::make_unique(this)) , _data(std::make_unique(this)) -, _user(_data->user(user)) +, _user(_data->processUser(user)) , _changelogs(Core::Changelogs::Create(this)) , _supportHelper(Support::Helper::Create(this)) { _saveDataTimer.setCallback([=] { Local::writeUserSettings(); }); - Messenger::Instance().passcodeLockChanges( + Core::App().passcodeLockChanges( ) | rpl::start_with_next([=] { _shouldLockAt = 0; }, _lifetime); - Messenger::Instance().lockChanges( + Core::App().lockChanges( ) | rpl::start_with_next([=] { notifications().updateAll(); }, _lifetime); @@ -429,10 +430,8 @@ } bool AuthSession::Exists() { - if (const auto messenger = Messenger::InstancePointer()) { - return (messenger->authSession() != nullptr); - } - return false; + return Core::Sandbox::Instance().applicationLaunched() + && (Core::App().authSession() != nullptr); } base::Observable &AuthSession::downloaderTaskFinished() { @@ -453,7 +452,7 @@ return false; } else if (user.c_user().vid.v != userId()) { LOG(("Auth Error: wrong self user received.")); - crl::on_main(this, [] { Messenger::Instance().logOut(); }); + crl::on_main(this, [] { Core::App().logOut(); }); return false; } return true; @@ -479,18 +478,18 @@ void AuthSession::checkAutoLock() { if (!Global::LocalPasscode() - || Messenger::Instance().passcodeLocked()) { + || Core::App().passcodeLocked()) { return; } - Messenger::Instance().checkLocalTime(); + Core::App().checkLocalTime(); auto now = getms(true); auto shouldLockInMs = Global::AutoLock() * 1000LL; auto idleForMs = psIdleTime(); auto notPlayingVideoForMs = now - settings().lastTimeVideoPlayedAt(); auto checkTimeMs = qMin(idleForMs, notPlayingVideoForMs); if (checkTimeMs >= shouldLockInMs || (_shouldLockAt > 0 && now > _shouldLockAt + kAutoLockTimeoutLateMs)) { - Messenger::Instance().lockByPasscode(); + Core::App().lockByPasscode(); } else { _shouldLockAt = now + (shouldLockInMs - checkTimeMs); _autoLockTimer.callOnce(shouldLockInMs - checkTimeMs); diff -Nru telegram-desktop-1.5.8/Telegram/SourceFiles/auth_session.h telegram-desktop-1.5.11/Telegram/SourceFiles/auth_session.h --- telegram-desktop-1.5.8/Telegram/SourceFiles/auth_session.h 2019-01-21 17:28:45.000000000 +0000 +++ telegram-desktop-1.5.11/Telegram/SourceFiles/auth_session.h 2019-02-01 12:51:46.000000000 +0000 @@ -267,7 +267,6 @@ }; -// One per Messenger. class AuthSession; AuthSession &Auth(); diff -Nru telegram-desktop-1.5.8/Telegram/SourceFiles/boxes/add_contact_box.cpp telegram-desktop-1.5.11/Telegram/SourceFiles/boxes/add_contact_box.cpp --- telegram-desktop-1.5.8/Telegram/SourceFiles/boxes/add_contact_box.cpp 2019-01-21 17:28:45.000000000 +0000 +++ telegram-desktop-1.5.11/Telegram/SourceFiles/boxes/add_contact_box.cpp 2019-02-01 12:51:46.000000000 +0000 @@ -10,7 +10,6 @@ #include "styles/style_boxes.h" #include "styles/style_dialogs.h" #include "lang/lang_keys.h" -#include "messenger.h" #include "mtproto/sender.h" #include "base/flat_set.h" #include "boxes/confirm_box.h" @@ -20,6 +19,7 @@ #include "boxes/peers/edit_participant_box.h" #include "boxes/peers/edit_participants_box.h" #include "core/file_utilities.h" +#include "core/application.h" #include "chat_helpers/emoji_suggestions_widget.h" #include "ui/widgets/checkbox.h" #include "ui/widgets/buttons.h" @@ -31,6 +31,7 @@ #include "data/data_channel.h" #include "data/data_chat.h" #include "data/data_user.h" +#include "data/data_session.h" #include "mainwidget.h" #include "mainwindow.h" #include "apiwrap.h" @@ -65,7 +66,7 @@ QString PeerFloodErrorText(PeerFloodType type) { auto link = textcmdLink( - Messenger::Instance().createInternalLinkFull(qsl("spambot")), + Core::App().createInternalLinkFull(qsl("spambot")), lang(lng_cant_more_info)); if (type == PeerFloodType::InviteGroup) { return lng_cant_invite_not_contact(lt_more_info, link); @@ -321,8 +322,9 @@ if (MTP::isDefaultHandledError(error)) return false; _addRequest = 0; - QString err(error.type()); - QString firstName = _first->getLastText().trimmed(), lastName = _last->getLastText().trimmed(); + const auto &err = error.type(); + const auto firstName = _first->getLastText().trimmed(); + const auto lastName = _last->getLastText().trimmed(); if (err == "CHAT_TITLE_NOT_MODIFIED") { _user->setName(firstName, lastName, _user->nameOrPhone, _user->username); closeBox(); @@ -340,14 +342,14 @@ if (!isBoxShown() || !App::main()) return; const auto &d = res.c_contacts_importedContacts(); - App::feedUsers(d.vusers); + Auth().data().processUsers(d.vusers); const auto &v = d.vimported.v; const auto user = [&]() -> UserData* { if (!v.isEmpty()) { auto &c = v.front().c_importedContact(); if (c.vclient_id.v == _contactId) { - return App::userLoaded(c.vuser_id.v); + return Auth().data().userLoaded(c.vuser_id.v); } } return nullptr; @@ -368,7 +370,7 @@ void AddContactBox::onSaveUserDone(const MTPcontacts_ImportedContacts &res) { auto &d = res.c_contacts_importedContacts(); - App::feedUsers(d.vusers); + Auth().data().processUsers(d.vusers); closeBox(); } @@ -535,7 +537,7 @@ : std::nullopt; } | [](auto chats) { - return App::chat(chats->front().c_chat().vid.v); + return Auth().data().chat(chats->front().c_chat().vid.v); } | [&](not_null chat) { if (!image.isNull()) { @@ -643,7 +645,7 @@ : std::nullopt; } | [](auto chats) { - return App::channel(chats->front().c_channel().vid.v); + return Auth().data().channel(chats->front().c_channel().vid.v); } | [&](not_null channel) { auto image = _photo->takeResultImage(); @@ -1153,7 +1155,7 @@ } void EditNameBox::saveSelfDone(const MTPUser &user) { - App::feedUsers(MTP_vector(1, user)); + _user->owner().processUsers(MTP_vector(1, user)); closeBox(); } @@ -1194,7 +1196,7 @@ return data.vchats.v; }); for (const auto &chat : chats) { - if (const auto peer = App::feedChat(chat)) { + if (const auto peer = Auth().data().processChat(chat)) { if (!peer->isChannel() || peer->userName().isEmpty()) { continue; } @@ -1207,7 +1209,7 @@ Ui::NameTextOptions()); row.status.setText( st::defaultTextStyle, - Messenger::Instance().createInternalLink( + Core::App().createInternalLink( textcmdLink(1, peer->userName())), Ui::DialogTextOptions()); _rows.push_back(std::move(row)); @@ -1282,7 +1284,7 @@ setCursor((_selected || _pressed) ? style::cur_pointer : style::cur_default); if (pressed && pressed == _selected) { auto text_method = pressed->isMegagroup() ? lng_channels_too_much_public_revoke_confirm_group : lng_channels_too_much_public_revoke_confirm_channel; - auto text = text_method(lt_link, Messenger::Instance().createInternalLink(pressed->userName()), lt_group, pressed->name); + auto text = text_method(lt_link, Core::App().createInternalLink(pressed->userName()), lt_group, pressed->name); auto confirmText = lang(lng_channels_too_much_public_revoke); _weakRevokeConfirmBox = Ui::show(Box(text, confirmText, crl::guard(this, [this, pressed]() { if (_revokeRequestId) return; diff -Nru telegram-desktop-1.5.8/Telegram/SourceFiles/boxes/background_box.cpp telegram-desktop-1.5.11/Telegram/SourceFiles/boxes/background_box.cpp --- telegram-desktop-1.5.8/Telegram/SourceFiles/boxes/background_box.cpp 2019-01-21 17:28:45.000000000 +0000 +++ telegram-desktop-1.5.11/Telegram/SourceFiles/boxes/background_box.cpp 2019-02-01 12:51:46.000000000 +0000 @@ -12,6 +12,7 @@ #include "mainwindow.h" #include "window/themes/window_theme.h" #include "ui/effects/round_checkbox.h" +#include "ui/toast/toast.h" #include "ui/image/image.h" #include "history/history.h" #include "history/history_message.h" @@ -21,6 +22,7 @@ #include "data/data_session.h" #include "data/data_user.h" #include "data/data_document.h" +#include "core/application.h" #include "boxes/confirm_box.h" #include "styles/style_overview.h" #include "styles/style_history.h" @@ -53,7 +55,7 @@ Expects(history->peer->isUser()); using Flag = MTPDmessage::Flag; - const auto id = ServerMaxMsgId + (ServerMaxMsgId / 3) + (out ? 1 : 0); + static auto id = ServerMaxMsgId + (ServerMaxMsgId / 3); const auto flags = Flag::f_entities | Flag::f_from_id | (out ? Flag::f_out : Flag(0)); @@ -61,7 +63,7 @@ const auto viaBotId = 0; const auto item = new HistoryMessage( history, - id, + ++id, flags, replyTo, viaBotId, @@ -72,9 +74,9 @@ return AdminLog::OwnedItem(delegate, item); } -QImage PrepareScaledFromFull( +QImage PrepareScaledNonPattern( const QImage &image, - Images::Option blur = Images::Option(0)) { + Images::Option blur) { const auto size = st::boxWideWidth; const auto width = std::max(image.width(), 1); const auto height = std::max(image.height(), 1); @@ -86,19 +88,74 @@ : (height * size / width); return Images::prepare( image, - takeWidth, - takeHeight, - Images::Option::Smooth | blur, + takeWidth * cIntRetinaFactor(), + takeHeight * cIntRetinaFactor(), + Images::Option::Smooth + | Images::Option::TransparentBackground + | blur, size, size); } -QPixmap PrepareScaledFromThumb(ImagePtr thumb) { - return thumb->loaded() - ? App::pixmapFromImageInPlace(PrepareScaledFromFull( - thumb->original(), - Images::Option::Blurred)) - : QPixmap(); +QImage ColorizePattern(QImage image, QColor color) { + if (image.format() != QImage::Format_ARGB32_Premultiplied) { + image = std::move(image).convertToFormat( + QImage::Format_ARGB32_Premultiplied); + } + // Similar to style::colorizeImage. + // But style::colorizeImage takes pattern with all pixels having the + // same components value, from (0, 0, 0, 0) to (255, 255, 255, 255). + // + // While in patterns we have different value ranges, usually they are + // from (0, 0, 0, 0) to (0, 0, 0, 255), so we should use only 'alpha'. + + const auto width = image.width(); + const auto height = image.height(); + const auto pattern = anim::shifted(color); + + const auto resultBytesPerPixel = (image.depth() >> 3); + constexpr auto resultIntsPerPixel = 1; + const auto resultIntsPerLine = (image.bytesPerLine() >> 2); + const auto resultIntsAdded = resultIntsPerLine - width * resultIntsPerPixel; + auto resultInts = reinterpret_cast(image.bits()); + Assert(resultIntsAdded >= 0); + Assert(image.depth() == static_cast((resultIntsPerPixel * sizeof(uint32)) << 3)); + Assert(image.bytesPerLine() == (resultIntsPerLine << 2)); + + const auto maskBytesPerPixel = (image.depth() >> 3); + const auto maskBytesPerLine = image.bytesPerLine(); + const auto maskBytesAdded = maskBytesPerLine - width * maskBytesPerPixel; + + // We want to read the last byte of four available. + // This is the difference with style::colorizeImage. + auto maskBytes = image.constBits() + (maskBytesPerPixel - 1); + Assert(maskBytesAdded >= 0); + Assert(image.depth() == (maskBytesPerPixel << 3)); + for (auto y = 0; y != height; ++y) { + for (auto x = 0; x != width; ++x) { + auto maskOpacity = static_cast(*maskBytes) + 1; + *resultInts = anim::unshifted(pattern * maskOpacity); + maskBytes += maskBytesPerPixel; + resultInts += resultIntsPerPixel; + } + maskBytes += maskBytesAdded; + resultInts += resultIntsAdded; + } + return image; +} + +QImage PrepareScaledFromFull( + const QImage &image, + std::optional patternBackground, + Images::Option blur = Images::Option(0)) { + auto result = PrepareScaledNonPattern(image, blur); + if (patternBackground) { + result = ColorizePattern( + std::move(result), + Data::PatternColor(*patternBackground)); + } + return std::move(result).convertToFormat( + QImage::Format_ARGB32_Premultiplied); } } // namespace @@ -124,6 +181,11 @@ private: void updateWallpapers(); + void paintPaper( + Painter &p, + const Data::WallPaper &paper, + int column, + int row) const; Fn _backgroundChosenCallback; @@ -153,9 +215,10 @@ void BackgroundBox::backgroundChosen(int index) { const auto &papers = Auth().data().wallpapers(); if (index >= 0 && index < papers.size()) { - App::main()->setChatBackground(papers[index]); + Ui::show( + Box(papers[index]), + LayerOption::KeepOther); } - closeBox(); } BackgroundBox::Inner::Inner(QWidget *parent) : RpWidget(parent) @@ -193,7 +256,7 @@ const auto preload = kBackgroundsInRow * 3; for (const auto &paper : papers | ranges::view::take(preload)) { - paper.thumb->load(Data::FileOrigin()); + paper.loadThumbnail(); } } @@ -220,24 +283,32 @@ }); if ((st::backgroundSize.height() + st::backgroundPadding) * (row + 1) <= r.top()) { continue; + } else if ((st::backgroundSize.height() + st::backgroundPadding) * row >= r.top() + r.height()) { + break; } + paintPaper(p, paper, column, row); + } +} - paper.thumb->load(Data::FileOrigin()); - - int x = st::backgroundPadding + column * (st::backgroundSize.width() + st::backgroundPadding); - int y = st::backgroundPadding + row * (st::backgroundSize.height() + st::backgroundPadding); - - const auto &pix = paper.thumb->pix( - Data::FileOrigin(), - st::backgroundSize.width(), - st::backgroundSize.height()); - p.drawPixmap(x, y, pix); - - if (paper.id == Window::Theme::Background()->id()) { - auto checkLeft = x + st::backgroundSize.width() - st::overviewCheckSkip - st::overviewCheck.size; - auto checkTop = y + st::backgroundSize.height() - st::overviewCheckSkip - st::overviewCheck.size; - _check->paint(p, getms(), checkLeft, checkTop, width()); - } +void BackgroundBox::Inner::paintPaper( + Painter &p, + const Data::WallPaper &paper, + int column, + int row) const { + Expects(paper.thumbnail() != nullptr); + + const auto x = st::backgroundPadding + column * (st::backgroundSize.width() + st::backgroundPadding); + const auto y = st::backgroundPadding + row * (st::backgroundSize.height() + st::backgroundPadding); + const auto &pixmap = paper.thumbnail()->pix( + paper.fileOrigin(), + st::backgroundSize.width(), + st::backgroundSize.height()); + p.drawPixmap(x, y, pixmap); + + if (paper.id() == Window::Theme::Background()->id()) { + const auto checkLeft = x + st::backgroundSize.width() - st::overviewCheckSkip - st::overviewCheck.size; + const auto checkTop = y + st::backgroundSize.height() - st::overviewCheckSkip - st::overviewCheck.size; + _check->paint(p, getms(), checkLeft, checkTop, width()); } } @@ -287,16 +358,18 @@ const Data::WallPaper &paper) : _text1(GenerateTextItem( this, - App::history(App::user(ServiceUserId)), + Auth().data().history(peerFromUser(ServiceUserId)), lang(lng_background_text1), false)) , _text2(GenerateTextItem( this, - App::history(App::user(ServiceUserId)), + Auth().data().history(peerFromUser(ServiceUserId)), lang(lng_background_text2), true)) , _paper(paper) , _radial(animation(this, &BackgroundPreviewBox::step_radial)) { + Expects(_paper.thumbnail() != nullptr); + subscribe(Auth().downloaderTaskFinished(), [=] { update(); }); } @@ -305,23 +378,18 @@ addButton(langFactory(lng_background_apply), [=] { apply(); }); addButton(langFactory(lng_cancel), [=] { closeBox(); }); + if (_paper.hasShareUrl()) { + addLeftButton(langFactory(lng_background_share), [=] { share(); }); + } + updateServiceBg(_paper.backgroundColor()); - _scaled = PrepareScaledFromThumb(_paper.thumb); - checkLoadedDocument(); - - if (_paper.thumb && !_paper.thumb->loaded()) { - _paper.thumb->loadEvenCancelled(Data::FileOriginWallpaper( - _paper.id, - _paper.accessHash)); - } - if (_paper.document) { - _paper.document->save(Data::FileOriginWallpaper( - _paper.id, - _paper.accessHash), QString()); - if (_paper.document->loading()) { - _radial.start(_paper.document->progress()); - } + _paper.loadThumbnail(); + _paper.loadDocument(); + if (_paper.document() && _paper.document()->loading()) { + _radial.start(_paper.document()->progress()); } + setScaledFromThumb(); + checkLoadedDocument(); _text1->setDisplayDate(true); _text1->initDimensions(); @@ -337,20 +405,23 @@ closeBox(); } +void BackgroundPreviewBox::share() { + QApplication::clipboard()->setText(_paper.shareUrl()); + Ui::Toast::Show(lang(lng_background_link_copied)); +} + void BackgroundPreviewBox::paintEvent(QPaintEvent *e) { Painter p(this); const auto ms = getms(); - - if (const auto color = Window::Theme::GetWallPaperColor(_paper.slug)) { + const auto color = _paper.backgroundColor(); + if (color) { p.fillRect(e->rect(), *color); - } else { - if (_scaled.isNull()) { - _scaled = PrepareScaledFromThumb(_paper.thumb); - if (_scaled.isNull()) { - p.fillRect(e->rect(), st::boxBg); - return; - } + } + if (!color || _paper.isPattern()) { + if (_scaled.isNull() && !setScaledFromThumb()) { + p.fillRect(e->rect(), st::boxBg); + return; } paintImage(p); paintRadial(p, ms); @@ -361,6 +432,11 @@ void BackgroundPreviewBox::paintImage(Painter &p) { Expects(!_scaled.isNull()); + p.setOpacity(_paper.isPattern() + ? std::clamp(_paper.patternIntensity() / 100., 0., 1.) + : 1.); + const auto guard = gsl::finally([&] { p.setOpacity(1.); }); + const auto factor = cIntRetinaFactor(); const auto size = st::boxWideWidth; const auto from = QRect( @@ -419,16 +495,37 @@ - height2 - st::historyPaddingBottom; p.translate(0, top); + paintDate(p); _text1->draw(p, rect(), TextSelection(), ms); p.translate(0, height1); _text2->draw(p, rect(), TextSelection(), ms); p.translate(0, height2); } +void BackgroundPreviewBox::paintDate(Painter &p) { + const auto date = _text1->Get(); + if (!date || !_serviceBg) { + return; + } + const auto text = date->text; + const auto bubbleHeight = st::msgServicePadding.top() + st::msgServiceFont->height + st::msgServicePadding.bottom(); + const auto bubbleTop = st::msgServiceMargin.top(); + const auto textWidth = st::msgServiceFont->width(text); + const auto bubbleWidth = st::msgServicePadding.left() + textWidth + st::msgServicePadding.right(); + const auto bubbleLeft = (width() - bubbleWidth) / 2; + const auto radius = bubbleHeight / 2; + p.setPen(Qt::NoPen); + p.setBrush(*_serviceBg); + p.drawRoundedRect(bubbleLeft, bubbleTop, bubbleWidth, bubbleHeight, radius, radius); + p.setPen(st::msgServiceFg); + p.setFont(st::msgServiceFont); + p.drawText(bubbleLeft + st::msgServicePadding.left(), bubbleTop + st::msgServicePadding.top() + st::msgServiceFont->ascent, text); +} + void BackgroundPreviewBox::step_radial(TimeMs ms, bool timer) { - Expects(_paper.document != nullptr); + Expects(_paper.document() != nullptr); - const auto document = _paper.document; + const auto document = _paper.document(); const auto wasAnimating = _radial.animating(); const auto updated = _radial.update( document->progress(), @@ -442,8 +539,39 @@ checkLoadedDocument(); } +bool BackgroundPreviewBox::setScaledFromThumb() { + Expects(_paper.thumbnail() != nullptr); + + const auto thumbnail = _paper.thumbnail(); + if (!thumbnail->loaded()) { + return false; + } + setScaledFromImage(PrepareScaledFromFull( + thumbnail->original(), + patternBackgroundColor(), + _paper.document() ? Images::Option::Blurred : Images::Option(0))); + return true; +} + +void BackgroundPreviewBox::setScaledFromImage(QImage &&image) { + updateServiceBg(Window::Theme::CountAverageColor(image)); + _scaled = App::pixmapFromImageInPlace(std::move(image)); +} + +void BackgroundPreviewBox::updateServiceBg(std::optional background) { + if (background) { + _serviceBg = Window::Theme::AdjustedColor( + st::msgServiceBg->c, + *background); + } +} + +std::optional BackgroundPreviewBox::patternBackgroundColor() const { + return _paper.isPattern() ? _paper.backgroundColor() : std::nullopt; +} + void BackgroundPreviewBox::checkLoadedDocument() { - const auto document = _paper.document; + const auto document = _paper.document(); if (!document || !document->loaded(DocumentData::FilePathResolveChecked) || _generating) { @@ -456,9 +584,10 @@ crl::async([ this, image = std::move(image), + patternBackground = patternBackgroundColor(), guard = std::move(right) ]() mutable { - auto scaled = PrepareScaledFromFull(image); + auto scaled = PrepareScaledFromFull(image, patternBackground); crl::on_main([ this, image = std::move(image), @@ -468,7 +597,7 @@ if (!guard) { return; } - _scaled = App::pixmapFromImageInPlace(std::move(scaled)); + setScaledFromImage(std::move(scaled)); _full = std::move(image); update(); }); @@ -476,22 +605,19 @@ }); } -bool BackgroundPreviewBox::Start(const QString &slug, const QString &mode) { - if (Window::Theme::GetWallPaperColor(slug)) { - Ui::show(Box(Data::WallPaper{ - Window::Theme::kCustomBackground, - 0ULL, // accessHash - MTPDwallPaper::Flags(0), - slug, - })); +bool BackgroundPreviewBox::Start( + const QString &slug, + const QMap ¶ms) { + if (const auto paper = Data::WallPaper::FromColorSlug(slug)) { + Ui::show(Box(paper->withUrlParams(params))); return true; } if (!IsValidWallPaperSlug(slug)) { Ui::show(Box(lang(lng_background_bad_link))); return false; } - Auth().api().requestWallPaper(slug, [](const Data::WallPaper &result) { - Ui::show(Box(result)); + Auth().api().requestWallPaper(slug, [=](const Data::WallPaper &result) { + Ui::show(Box(result.withUrlParams(params))); }, [](const RPCError &error) { Ui::show(Box(lang(lng_background_bad_link))); }); diff -Nru telegram-desktop-1.5.8/Telegram/SourceFiles/boxes/background_box.h telegram-desktop-1.5.11/Telegram/SourceFiles/boxes/background_box.h --- telegram-desktop-1.5.8/Telegram/SourceFiles/boxes/background_box.h 2019-01-21 17:28:45.000000000 +0000 +++ telegram-desktop-1.5.11/Telegram/SourceFiles/boxes/background_box.h 2019-02-01 12:51:46.000000000 +0000 @@ -39,7 +39,9 @@ public: BackgroundPreviewBox(QWidget*, const Data::WallPaper &paper); - static bool Start(const QString &slug, const QString &mode); + static bool Start( + const QString &slug, + const QMap ¶ms); using Element = HistoryView::Element; HistoryView::Context elementContext() override; @@ -61,13 +63,19 @@ private: void apply(); + void share(); void step_radial(TimeMs ms, bool timer); QRect radialRect() const; void checkLoadedDocument(); + bool setScaledFromThumb(); + void setScaledFromImage(QImage &&image); + void updateServiceBg(std::optional background); + std::optional patternBackgroundColor() const; void paintImage(Painter &p); void paintRadial(Painter &p, TimeMs ms); void paintTexts(Painter &p, TimeMs ms); + void paintDate(Painter &p); AdminLog::OwnedItem _text1; AdminLog::OwnedItem _text2; @@ -76,5 +84,6 @@ QPixmap _scaled; Ui::RadialAnimation _radial; base::binary_guard _generating; + std::optional _serviceBg; }; diff -Nru telegram-desktop-1.5.8/Telegram/SourceFiles/boxes/boxes.style telegram-desktop-1.5.11/Telegram/SourceFiles/boxes/boxes.style --- telegram-desktop-1.5.8/Telegram/SourceFiles/boxes/boxes.style 2019-01-21 17:28:45.000000000 +0000 +++ telegram-desktop-1.5.11/Telegram/SourceFiles/boxes/boxes.style 2019-02-01 12:51:46.000000000 +0000 @@ -69,7 +69,7 @@ linkFontOver: font(17px semibold underline); } } -boxTitlePosition: point(23px, 20px); +boxTitlePosition: point(23px, 16px); boxTitleHeight: 56px; boxLayerTitlePosition: point(23px, 16px); boxLayerTitleHeight: 56px; diff -Nru telegram-desktop-1.5.8/Telegram/SourceFiles/boxes/calendar_box.cpp telegram-desktop-1.5.11/Telegram/SourceFiles/boxes/calendar_box.cpp --- telegram-desktop-1.5.8/Telegram/SourceFiles/boxes/calendar_box.cpp 2019-01-21 17:28:45.000000000 +0000 +++ telegram-desktop-1.5.11/Telegram/SourceFiles/boxes/calendar_box.cpp 2019-02-01 12:51:46.000000000 +0000 @@ -495,16 +495,8 @@ } void CalendarBox::prepare() { - _previous->setClickedCallback([this] { - if (isPreviousEnabled()) { - _context->skipMonth(-1); - } - }); - _next->setClickedCallback([this] { - if (isNextEnabled()) { - _context->skipMonth(1); - } - }); + _previous->setClickedCallback([this] { goPreviousMonth(); }); + _next->setClickedCallback([this] { goNextMonth(); }); // _inner = setInnerWidget(object_ptr(this, _context.get()), st::calendarScroll, st::calendarTitleHeight); _inner->setDateChosenCallback(std::move(_callback)); @@ -528,6 +520,18 @@ return (_context->maxDayIndex() >= _context->daysCount()); } +void CalendarBox::goPreviousMonth() { + if (isPreviousEnabled()) { + _context->skipMonth(-1); + } +} + +void CalendarBox::goNextMonth() { + if (isNextEnabled()) { + _context->skipMonth(1); + } +} + void CalendarBox::monthChanged(QDate month) { setDimensions(_st.width, st::calendarTitleHeight + _inner->countHeight()); auto previousEnabled = isPreviousEnabled(); @@ -548,4 +552,14 @@ BoxContent::resizeEvent(e); } +void CalendarBox::keyPressEvent(QKeyEvent *e) { + if (e->key() == Qt::Key_Escape) { + e->ignore(); + } else if (e->key() == Qt::Key_Left) { + goPreviousMonth(); + } else if (e->key() == Qt::Key_Right) { + goNextMonth(); + } +} + CalendarBox::~CalendarBox() = default; diff -Nru telegram-desktop-1.5.8/Telegram/SourceFiles/boxes/calendar_box.h telegram-desktop-1.5.11/Telegram/SourceFiles/boxes/calendar_box.h --- telegram-desktop-1.5.8/Telegram/SourceFiles/boxes/calendar_box.h 2019-01-21 17:28:45.000000000 +0000 +++ telegram-desktop-1.5.11/Telegram/SourceFiles/boxes/calendar_box.h 2019-02-01 12:51:46.000000000 +0000 @@ -42,6 +42,7 @@ protected: void prepare() override; + void keyPressEvent(QKeyEvent *e) override; void resizeEvent(QResizeEvent *e) override; private: @@ -50,6 +51,9 @@ bool isPreviousEnabled() const; bool isNextEnabled() const; + void goPreviousMonth(); + void goNextMonth(); + const style::CalendarSizes &_st; class Context; diff -Nru telegram-desktop-1.5.8/Telegram/SourceFiles/boxes/change_phone_box.cpp telegram-desktop-1.5.11/Telegram/SourceFiles/boxes/change_phone_box.cpp --- telegram-desktop-1.5.8/Telegram/SourceFiles/boxes/change_phone_box.cpp 2019-01-21 17:28:45.000000000 +0000 +++ telegram-desktop-1.5.11/Telegram/SourceFiles/boxes/change_phone_box.cpp 2019-02-01 12:51:46.000000000 +0000 @@ -8,13 +8,15 @@ #include "boxes/change_phone_box.h" #include "lang/lang_keys.h" -#include "styles/style_boxes.h" #include "ui/widgets/labels.h" #include "ui/widgets/input_fields.h" #include "ui/wrap/fade_wrap.h" #include "boxes/confirm_phone_box.h" #include "ui/toast/toast.h" #include "boxes/confirm_box.h" +#include "auth_session.h" +#include "data/data_session.h" +#include "styles/style_boxes.h" namespace { @@ -144,11 +146,19 @@ hideError(); auto phoneNumber = _phone->getLastText().trimmed(); - _requestId = MTP::send(MTPaccount_SendChangePhoneCode(MTP_flags(0), MTP_string(phoneNumber), MTP_bool(false)), rpcDone(crl::guard(this, [this, phoneNumber](const MTPauth_SentCode &result) { - return sendPhoneDone(phoneNumber, result); - })), rpcFail(crl::guard(this, [this, phoneNumber](const RPCError &error) { - return sendPhoneFail(phoneNumber, error); - }))); + _requestId = MTP::send( + MTPaccount_SendChangePhoneCode( + MTP_string(phoneNumber), + MTP_codeSettings( + MTP_flags(0), + MTPstring())), + rpcDone(crl::guard(this, [=]( + const MTPauth_SentCode &result) { + return sendPhoneDone(phoneNumber, result); + })), rpcFail(crl::guard(this, [=]( + const RPCError &error) { + return sendPhoneFail(phoneNumber, error); + }))); } void ChangePhoneBox::EnterPhone::sendPhoneDone(const QString &phoneNumber, const MTPauth_SentCode &result) { @@ -260,7 +270,7 @@ MTP_string(_hash), MTP_string(code) ), rpcDone([weak = make_weak(this)](const MTPUser &result) { - App::feedUser(result); + Auth().data().processUser(result); if (weak) { Ui::hideLayer(); } diff -Nru telegram-desktop-1.5.8/Telegram/SourceFiles/boxes/confirm_box.cpp telegram-desktop-1.5.11/Telegram/SourceFiles/boxes/confirm_box.cpp --- telegram-desktop-1.5.8/Telegram/SourceFiles/boxes/confirm_box.cpp 2019-01-21 17:28:45.000000000 +0000 +++ telegram-desktop-1.5.11/Telegram/SourceFiles/boxes/confirm_box.cpp 2019-02-01 12:51:46.000000000 +0000 @@ -12,7 +12,6 @@ #include "mainwidget.h" #include "mainwindow.h" #include "apiwrap.h" -#include "application.h" #include "history/history.h" #include "history/history_item.h" #include "ui/widgets/checkbox.h" @@ -689,7 +688,7 @@ auto result = std::vector>(); result.reserve(v.size()); for (const auto &participant : v) { - if (const auto user = App::feedUser(participant)) { + if (const auto user = Auth().data().processUser(participant)) { result.push_back(user); } } diff -Nru telegram-desktop-1.5.8/Telegram/SourceFiles/boxes/confirm_phone_box.cpp telegram-desktop-1.5.11/Telegram/SourceFiles/boxes/confirm_phone_box.cpp --- telegram-desktop-1.5.8/Telegram/SourceFiles/boxes/confirm_phone_box.cpp 2019-01-21 17:28:45.000000000 +0000 +++ telegram-desktop-1.5.11/Telegram/SourceFiles/boxes/confirm_phone_box.cpp 2019-02-01 12:51:46.000000000 +0000 @@ -170,7 +170,14 @@ if (_sendCodeRequestId) { return; } - _sendCodeRequestId = MTP::send(MTPaccount_SendConfirmPhoneCode(MTP_flags(0), MTP_string(_hash), MTPBool()), rpcDone(&ConfirmPhoneBox::sendCodeDone), rpcFail(&ConfirmPhoneBox::sendCodeFail)); + _sendCodeRequestId = MTP::send( + MTPaccount_SendConfirmPhoneCode( + MTP_string(_hash), + MTP_codeSettings( + MTP_flags(0), + MTPstring())), + rpcDone(&ConfirmPhoneBox::sendCodeDone), + rpcFail(&ConfirmPhoneBox::sendCodeFail)); } void ConfirmPhoneBox::sendCodeDone(const MTPauth_SentCode &result) { diff -Nru telegram-desktop-1.5.8/Telegram/SourceFiles/boxes/connection_box.cpp telegram-desktop-1.5.11/Telegram/SourceFiles/boxes/connection_box.cpp --- telegram-desktop-1.5.8/Telegram/SourceFiles/boxes/connection_box.cpp 2019-01-21 17:28:45.000000000 +0000 +++ telegram-desktop-1.5.11/Telegram/SourceFiles/boxes/connection_box.cpp 2019-02-01 12:51:46.000000000 +0000 @@ -11,7 +11,7 @@ #include "lang/lang_keys.h" #include "storage/localstorage.h" #include "base/qthelp_url.h" -#include "messenger.h" +#include "core/application.h" #include "ui/widgets/checkbox.h" #include "ui/widgets/buttons.h" #include "ui/widgets/input_fields.h" @@ -975,7 +975,7 @@ if (ranges::find(proxies, proxy) == end(proxies)) { proxies.push_back(proxy); } - Messenger::Instance().setCurrentProxy( + Core::App().setCurrentProxy( proxy, ProxyData::Settings::Enabled); Local::writeSettings(); @@ -998,7 +998,7 @@ const auto type = (item.data.type == Type::Http) ? Variants::Http : Variants::Tcp; - const auto mtproto = Messenger::Instance().mtp(); + const auto mtproto = Core::App().mtp(); const auto dcId = mtproto->mainDcId(); item.state = ItemState::Checking; @@ -1140,7 +1140,7 @@ auto j = findByProxy(Global::SelectedProxy()); - Messenger::Instance().setCurrentProxy( + Core::App().setCurrentProxy( item->data, ProxyData::Settings::Enabled); saveDelayed(); @@ -1163,7 +1163,7 @@ _lastSelectedProxy = base::take(Global::RefSelectedProxy()); if (Global::ProxySettings() == ProxyData::Settings::Enabled) { _lastSelectedProxyUsed = true; - Messenger::Instance().setCurrentProxy( + Core::App().setCurrentProxy( ProxyData(), ProxyData::Settings::System); saveDelayed(); @@ -1188,7 +1188,7 @@ Assert(Global::ProxySettings() != ProxyData::Settings::Enabled); if (base::take(_lastSelectedProxyUsed)) { - Messenger::Instance().setCurrentProxy( + Core::App().setCurrentProxy( base::take(_lastSelectedProxy), ProxyData::Settings::Enabled); } else { @@ -1293,9 +1293,7 @@ } } } - Messenger::Instance().setCurrentProxy( - Global::SelectedProxy(), - value); + Core::App().setCurrentProxy(Global::SelectedProxy(), value); saveDelayed(); return true; } diff -Nru telegram-desktop-1.5.8/Telegram/SourceFiles/boxes/edit_caption_box.cpp telegram-desktop-1.5.11/Telegram/SourceFiles/boxes/edit_caption_box.cpp --- telegram-desktop-1.5.8/Telegram/SourceFiles/boxes/edit_caption_box.cpp 2019-01-21 17:28:45.000000000 +0000 +++ telegram-desktop-1.5.11/Telegram/SourceFiles/boxes/edit_caption_box.cpp 2019-02-01 12:51:46.000000000 +0000 @@ -42,17 +42,17 @@ Expects(item->media()->allowsEditCaption()); QSize dimensions; - ImagePtr image; + auto image = (Image*)nullptr; DocumentData *doc = nullptr; const auto media = item->media(); if (const auto photo = media->photo()) { _photo = true; - dimensions = QSize(photo->full->width(), photo->full->height()); - image = photo->full; + dimensions = QSize(photo->width(), photo->height()); + image = photo->large(); } else if (const auto document = media->document()) { dimensions = document->dimensions; - image = document->thumb; + image = document->thumbnail(); if (document->isAnimation()) { _animated = true; } else if (document->isVideoFile()) { @@ -68,8 +68,8 @@ ConvertEntitiesToTextTags(original.entities) }; - if (!_animated && (dimensions.isEmpty() || doc || image->isNull())) { - if (image->isNull()) { + if (!_animated && (dimensions.isEmpty() || doc || !image)) { + if (!image) { _thumbw = 0; } else { int32 tw = image->width(), th = image->height(); diff -Nru telegram-desktop-1.5.8/Telegram/SourceFiles/boxes/edit_caption_box.h telegram-desktop-1.5.11/Telegram/SourceFiles/boxes/edit_caption_box.h --- telegram-desktop-1.5.8/Telegram/SourceFiles/boxes/edit_caption_box.h 2019-01-21 17:28:45.000000000 +0000 +++ telegram-desktop-1.5.11/Telegram/SourceFiles/boxes/edit_caption_box.h 2019-02-01 12:51:46.000000000 +0000 @@ -63,7 +63,7 @@ not_null _controller; FullMsgId _msgId; - ImagePtr _thumbnailImage; + Image *_thumbnailImage = nullptr; bool _thumbnailImageLoaded = false; Fn _refreshThumbnail; bool _animated = false; diff -Nru telegram-desktop-1.5.8/Telegram/SourceFiles/boxes/language_box.cpp telegram-desktop-1.5.11/Telegram/SourceFiles/boxes/language_box.cpp --- telegram-desktop-1.5.8/Telegram/SourceFiles/boxes/language_box.cpp 2019-01-21 17:28:45.000000000 +0000 +++ telegram-desktop-1.5.11/Telegram/SourceFiles/boxes/language_box.cpp 2019-02-01 12:51:46.000000000 +0000 @@ -24,7 +24,7 @@ #include "boxes/confirm_box.h" #include "mainwidget.h" #include "mainwindow.h" -#include "messenger.h" +#include "core/application.h" #include "lang/lang_instance.h" #include "lang/lang_cloud_manager.h" #include "styles/style_boxes.h" @@ -1132,7 +1132,7 @@ base::binary_guard LanguageBox::Show() { auto result = base::binary_guard(); - const auto manager = Messenger::Instance().langCloudManager(); + const auto manager = Core::App().langCloudManager(); if (manager->languageList().empty()) { auto guard = std::make_shared(); std::tie(result, *guard) = base::make_binary_guard(); diff -Nru telegram-desktop-1.5.8/Telegram/SourceFiles/boxes/peer_list_box.cpp telegram-desktop-1.5.11/Telegram/SourceFiles/boxes/peer_list_box.cpp --- telegram-desktop-1.5.8/Telegram/SourceFiles/boxes/peer_list_box.cpp 2019-01-21 17:28:45.000000000 +0000 +++ telegram-desktop-1.5.11/Telegram/SourceFiles/boxes/peer_list_box.cpp 2019-02-01 12:51:46.000000000 +0000 @@ -27,6 +27,7 @@ #include "storage/file_download.h" #include "data/data_peer_values.h" #include "data/data_chat.h" +#include "data/data_session.h" #include "window/themes/window_theme.h" auto PaintUserpicCallback( @@ -64,7 +65,7 @@ _select->entity()->setSubmittedCallback([this](Qt::KeyboardModifiers) { content()->submitted(); }); _select->entity()->setQueryChangedCallback([this](const QString &query) { searchQueryChanged(query); }); _select->entity()->setItemRemovedCallback([this](uint64 itemId) { - if (auto peer = App::peerLoaded(itemId)) { + if (auto peer = Auth().data().peerLoaded(itemId)) { if (auto row = peerListFindRow(peer->id)) { content()->changeCheckState(row, false, PeerListRow::SetStyle::Animated); update(); @@ -327,7 +328,7 @@ if (!items.empty()) { result.reserve(items.size()); for (const auto itemId : items) { - result.push_back(App::peer(itemId)); + result.push_back(Auth().data().peer(itemId)); } } return result; diff -Nru telegram-desktop-1.5.8/Telegram/SourceFiles/boxes/peer_list_controllers.cpp telegram-desktop-1.5.11/Telegram/SourceFiles/boxes/peer_list_controllers.cpp --- telegram-desktop-1.5.8/Telegram/SourceFiles/boxes/peer_list_controllers.cpp 2019-01-21 17:28:45.000000000 +0000 +++ telegram-desktop-1.5.11/Telegram/SourceFiles/boxes/peer_list_controllers.cpp 2019-02-01 12:51:46.000000000 +0000 @@ -26,7 +26,7 @@ namespace { void ShareBotGame(not_null bot, not_null chat) { - const auto history = App::historyLoaded(chat); + const auto history = chat->owner().historyLoaded(chat); const auto randomId = rand_value(); const auto requestId = MTP::send( MTPmessages_SendMedia( @@ -182,8 +182,8 @@ auto &contacts = result.c_contacts_found(); auto query = _query; if (requestId) { - App::feedUsers(contacts.vusers); - App::feedChats(contacts.vchats); + Auth().data().processUsers(contacts.vusers); + Auth().data().processChats(contacts.vchats); auto it = _queries.find(requestId); if (it != _queries.cend()) { query = it->second; @@ -193,7 +193,7 @@ } const auto feedList = [&](const MTPVector &list) { for (const auto &mtpPeer : list.v) { - if (const auto peer = App::peerLoaded(peerFromMTP(mtpPeer))) { + if (const auto peer = Auth().data().peerLoaded(peerFromMTP(mtpPeer))) { delegate()->peerListSearchAddRow(peer); } } @@ -255,7 +255,7 @@ }; auto added = 0; if (respectSavedMessagesChat()) { - if (appendRow(App::history(Auth().user()))) { + if (appendRow(Auth().data().history(Auth().user()))) { ++added; } } @@ -292,7 +292,7 @@ } std::unique_ptr ChatsListBoxController::createSearchRow(not_null peer) { - return createRow(App::history(peer)); + return createRow(peer->owner().history(peer)); } bool ChatsListBoxController::appendRow(not_null history) { diff -Nru telegram-desktop-1.5.8/Telegram/SourceFiles/boxes/peers/add_participants_box.cpp telegram-desktop-1.5.11/Telegram/SourceFiles/boxes/peers/add_participants_box.cpp --- telegram-desktop-1.5.8/Telegram/SourceFiles/boxes/peers/add_participants_box.cpp 2019-01-21 17:28:45.000000000 +0000 +++ telegram-desktop-1.5.11/Telegram/SourceFiles/boxes/peers/add_participants_box.cpp 2019-02-01 12:51:46.000000000 +0000 @@ -13,6 +13,7 @@ #include "data/data_channel.h" #include "data/data_chat.h" #include "data/data_user.h" +#include "data/data_session.h" #include "history/history.h" #include "dialogs/dialogs_indexed_list.h" #include "auth_session.h" @@ -435,7 +436,7 @@ Expects(result.type() == mtpc_channels_channelParticipant); const auto &participant = result.c_channels_channelParticipant(); - App::feedUsers(participant.vusers); + channel->owner().processUsers(participant.vusers); _additional.applyParticipant(participant.vparticipant); callback(); }).fail([=](const RPCError &error) { @@ -709,27 +710,30 @@ // Finally kick him. if (!sure) { const auto text = ((_peer->isChat() || _peer->isMegagroup()) - ? lng_sure_remove_user_group - : lng_sure_remove_user_channel)(lt_user, App::peerName(user)); + ? lng_profile_sure_kick + : lng_profile_sure_kick_channel)(lt_user, App::peerName(user)); _editBox = Ui::show( Box(text, kickUserSure), LayerOption::KeepOther); return; } - _editBox = nullptr; const auto restrictedRights = _additional.restrictedRights(user); const auto currentRights = restrictedRights ? *restrictedRights : MTPChatBannedRights(MTP_chatBannedRights( MTP_flags(0), MTP_int(0))); - auto &session = _peer->session(); - if (const auto chat = _peer->asChat()) { - session.api().kickParticipant(chat, user); - } else if (const auto channel = _peer->asChannel()) { - session.api().kickParticipant(channel, user, currentRights); - } + + const auto done = crl::guard(this, [=]( + const MTPChatBannedRights &newRights) { + editRestrictedDone(user, newRights); + }); + const auto fail = crl::guard(this, [=] { + _editBox = nullptr; + }); + const auto callback = SaveRestrictedCallback(_peer, user, done, fail); + callback(currentRights, ChannelData::KickedRestrictedRights()); } bool AddSpecialBoxController::appendRow(not_null user) { @@ -964,8 +968,8 @@ auto &found = result.c_contacts_found(); auto query = _query; if (requestId) { - App::feedUsers(found.vusers); - App::feedChats(found.vchats); + _peer->owner().processUsers(found.vusers); + _peer->owner().processChats(found.vchats); auto it = _globalQueries.find(requestId); if (it != _globalQueries.cend()) { query = it->second; @@ -977,7 +981,7 @@ const auto feedList = [&](const MTPVector &list) { for (const auto &mtpPeer : list.v) { const auto peerId = peerFromMTP(mtpPeer); - if (const auto peer = App::peerLoaded(peerId)) { + if (const auto peer = _peer->owner().peerLoaded(peerId)) { if (const auto user = peer->asUser()) { _additional->checkForLoaded(user); delegate()->peerListSearchAddRow(user); diff -Nru telegram-desktop-1.5.8/Telegram/SourceFiles/boxes/peers/add_participants_box.h telegram-desktop-1.5.11/Telegram/SourceFiles/boxes/peers/add_participants_box.h --- telegram-desktop-1.5.8/Telegram/SourceFiles/boxes/peers/add_participants_box.h 2019-01-21 17:28:45.000000000 +0000 +++ telegram-desktop-1.5.11/Telegram/SourceFiles/boxes/peers/add_participants_box.h 2019-02-01 12:51:46.000000000 +0000 @@ -95,10 +95,6 @@ not_null user, const MTPChatBannedRights &rights); void kickUser(not_null user, bool sure = false); - void restrictUserSure( - not_null user, - const MTPChatBannedRights &oldRights, - const MTPChatBannedRights &newRights); bool appendRow(not_null user); bool prependRow(not_null user); std::unique_ptr createRow(not_null user) const; diff -Nru telegram-desktop-1.5.8/Telegram/SourceFiles/boxes/peers/edit_participant_box.cpp telegram-desktop-1.5.11/Telegram/SourceFiles/boxes/peers/edit_participant_box.cpp --- telegram-desktop-1.5.8/Telegram/SourceFiles/boxes/peers/edit_participant_box.cpp 2019-01-21 17:28:45.000000000 +0000 +++ telegram-desktop-1.5.11/Telegram/SourceFiles/boxes/peers/edit_participant_box.cpp 2019-02-01 12:51:46.000000000 +0000 @@ -212,7 +212,9 @@ const auto chat = peer()->asChat(); const auto channel = peer()->asChannel(); const auto prepareRights = hadRights ? _oldRights : Defaults(peer()); - const auto disabledByDefaults = DisabledByDefaultRestrictions(peer()); + const auto disabledByDefaults = (channel && !channel->isMegagroup()) + ? MTPDchatAdminRights::Flags(0) + : DisabledByDefaultRestrictions(peer()); const auto filterByMyRights = canSave() && !hadRights && channel diff -Nru telegram-desktop-1.5.8/Telegram/SourceFiles/boxes/peers/edit_participants_box.cpp telegram-desktop-1.5.11/Telegram/SourceFiles/boxes/peers/edit_participants_box.cpp --- telegram-desktop-1.5.8/Telegram/SourceFiles/boxes/peers/edit_participants_box.cpp 2019-01-21 17:28:45.000000000 +0000 +++ telegram-desktop-1.5.11/Telegram/SourceFiles/boxes/peers/edit_participants_box.cpp 2019-02-01 12:51:46.000000000 +0000 @@ -179,6 +179,26 @@ }).send(); } +void SaveChatParticipantKick( + not_null chat, + not_null user, + Fn onDone, + Fn onFail) { + chat->session().api().request(MTPmessages_DeleteChatUser( + chat->inputChat, + user->inputUser + )).done([=](const MTPUpdates &result) { + chat->session().api().applyUpdates(result); + if (onDone) { + onDone(); + } + }).fail([=](const RPCError &error) { + if (onFail) { + onFail(); + } + }).send(); +} + } // namespace Fnsession().api().migrateChat(chat, saveForChannel); @@ -1333,8 +1355,6 @@ kickMember(user); } else if (_role == Role::Admins) { removeAdmin(user); - } else if (_role == Role::Restricted) { - showRestricted(user); } else { removeKicked(row, user); } @@ -1377,13 +1397,19 @@ crl::guard(this, [=] { showAdmin(user); })); } if (_additional.canRestrictUser(user)) { - const auto isGroup = _peer->isChat() || _peer->isMegagroup(); - if (isGroup) { + const auto canRestrictWithoutKick = [&] { + if (const auto chat = _peer->asChat()) { + return chat->amCreator(); + } + return _peer->isMegagroup(); + }(); + if (canRestrictWithoutKick) { result->addAction( lang(lng_context_restrict_user), crl::guard(this, [=] { showRestricted(user); })); } if (!_additional.isKicked(user)) { + const auto isGroup = _peer->isChat() || _peer->isMegagroup(); result->addAction( lang(isGroup ? lng_context_remove_from_group @@ -1622,6 +1648,10 @@ not_null row, not_null user) { delegate()->peerListRemoveRow(row); + if (_role != Role::Kicked + && !delegate()->peerListFullRowsCount()) { + setDescriptionText(lang(lng_blocked_list_not_found)); + } delegate()->peerListRefreshRows(); removeKicked(user); } @@ -1686,8 +1716,10 @@ && _additional.adminRights(user).has_value() && _additional.canEditAdmin(user)) { row->setActionLink(lang(lng_profile_kick)); - } else if (_role == Role::Kicked) { - row->setActionLink(lang(lng_profile_delete_removed)); + } else if (_role == Role::Kicked || _role == Role::Restricted) { + if (_additional.canRestrictUser(user)) { + row->setActionLink(lang(lng_profile_delete_removed)); + } } else if (_role == Role::Members) { if ((chat ? chat->canBanMembers() : channel->canBanMembers()) && !_additional.isCreator(user) diff -Nru telegram-desktop-1.5.8/Telegram/SourceFiles/boxes/peers/edit_peer_info_box.cpp telegram-desktop-1.5.11/Telegram/SourceFiles/boxes/peers/edit_peer_info_box.cpp --- telegram-desktop-1.5.8/Telegram/SourceFiles/boxes/peers/edit_peer_info_box.cpp 2019-01-21 17:28:45.000000000 +0000 +++ telegram-desktop-1.5.11/Telegram/SourceFiles/boxes/peers/edit_peer_info_box.cpp 2019-02-01 12:51:46.000000000 +0000 @@ -31,7 +31,7 @@ #include "mtproto/sender.h" #include "lang/lang_keys.h" #include "mainwidget.h" -#include "messenger.h" +#include "core/application.h" #include "apiwrap.h" #include "auth_session.h" #include "observer_peer.h" diff -Nru telegram-desktop-1.5.8/Telegram/SourceFiles/boxes/share_box.cpp telegram-desktop-1.5.11/Telegram/SourceFiles/boxes/share_box.cpp --- telegram-desktop-1.5.8/Telegram/SourceFiles/boxes/share_box.cpp 2019-01-21 17:28:45.000000000 +0000 +++ telegram-desktop-1.5.11/Telegram/SourceFiles/boxes/share_box.cpp 2019-02-01 12:51:46.000000000 +0000 @@ -31,8 +31,9 @@ #include "chat_helpers/emoji_suggestions_widget.h" #include "data/data_channel.h" #include "data/data_user.h" +#include "data/data_session.h" #include "auth_session.h" -#include "messenger.h" +#include "core/application.h" #include "styles/style_boxes.h" #include "styles/style_history.h" @@ -220,7 +221,7 @@ applyFilterUpdate(query); }); _select->setItemRemovedCallback([=](uint64 itemId) { - if (const auto peer = App::peerLoaded(itemId)) { + if (const auto peer = Auth().data().peerLoaded(itemId)) { _inner->peerUnselected(peer); selectedChanged(); update(); @@ -334,8 +335,8 @@ switch (result.type()) { case mtpc_contacts_found: { auto &found = result.c_contacts_found(); - App::feedUsers(found.vusers); - App::feedChats(found.vchats); + Auth().data().processUsers(found.vusers); + Auth().data().processChats(found.vchats); _inner->peopleReceived( query, found.vmy_results.v, @@ -491,7 +492,7 @@ const auto dialogs = App::main()->dialogsList(); const auto self = Auth().user(); if (_filterCallback(self)) { - _chatsIndexed->addToEnd(App::history(self)); + _chatsIndexed->addToEnd(self->owner().history(self)); } for (const auto row : dialogs->all()) { if (const auto history = row->history()) { @@ -880,7 +881,7 @@ if (!chat) return; if (!_filter.isEmpty()) { - const auto history = App::history(chat->peer); + const auto history = chat->peer->owner().history(chat->peer); auto row = _chatsIndexed->getRow(history); if (!row) { const auto rowsByLetter = _chatsIndexed->addToEnd(history); @@ -1017,8 +1018,8 @@ d_byUsernameFiltered.reserve(already + my.size() + people.size()); const auto feedList = [&](const QVector &list) { for (const auto &data : list) { - if (const auto peer = App::peerLoaded(peerFromMTP(data))) { - const auto history = App::historyLoaded(peer); + if (const auto peer = Auth().data().peerLoaded(peerFromMTP(data))) { + const auto history = Auth().data().historyLoaded(peer); if (!_filterCallback(peer)) { continue; } else if (history && _chatsIndexed->getRow(history)) { @@ -1066,7 +1067,9 @@ QString AppendShareGameScoreUrl(const QString &url, const FullMsgId &fullId) { auto shareHashData = QByteArray(0x10, Qt::Uninitialized); auto shareHashDataInts = reinterpret_cast(shareHashData.data()); - auto channel = fullId.channel ? App::channelLoaded(fullId.channel) : static_cast(nullptr); + auto channel = fullId.channel + ? Auth().data().channelLoaded(fullId.channel) + : static_cast(nullptr); auto channelAccessHash = channel ? channel->access : 0ULL; auto channelAccessHashInts = reinterpret_cast(&channelAccessHash); shareHashDataInts[0] = Auth().userId(); @@ -1169,7 +1172,9 @@ }); }; - auto channel = channelId ? App::channelLoaded(channelId) : nullptr; + const auto channel = channelId + ? Auth().data().channelLoaded(channelId) + : nullptr; if (channel || !channelId) { resolveMessageAndShareScore(channel); } else { @@ -1177,9 +1182,9 @@ auto requestChannel = MTPchannels_GetChannels(requestChannelIds); MTP::send(requestChannel, rpcDone([=](const MTPmessages_Chats &result) { result.match([](const auto &data) { - App::feedChats(data.vchats); + Auth().data().processChats(data.vchats); }); - if (const auto channel = App::channelLoaded(channelId)) { + if (const auto channel = Auth().data().channelLoaded(channelId)) { resolveMessageAndShareScore(channel); } })); diff -Nru telegram-desktop-1.5.8/Telegram/SourceFiles/boxes/stickers_box.cpp telegram-desktop-1.5.11/Telegram/SourceFiles/boxes/stickers_box.cpp --- telegram-desktop-1.5.8/Telegram/SourceFiles/boxes/stickers_box.cpp 2019-01-21 17:28:45.000000000 +0000 +++ telegram-desktop-1.5.11/Telegram/SourceFiles/boxes/stickers_box.cpp 2019-02-01 12:51:46.000000000 +0000 @@ -10,6 +10,7 @@ #include "data/data_document.h" #include "data/data_session.h" #include "data/data_channel.h" +#include "core/application.h" #include "lang/lang_keys.h" #include "mainwidget.h" #include "chat_helpers/stickers.h" @@ -30,7 +31,6 @@ #include "ui/widgets/input_fields.h" #include "ui/image/image.h" #include "auth_session.h" -#include "messenger.h" namespace { @@ -623,7 +623,7 @@ , _megagroupSetField(this, st::groupStickersField, [] { return qsl("stickerset"); }, QString(), true) , _megagroupDivider(this) , _megagroupSubTitle(this, lang(lng_stickers_group_from_your), Ui::FlatLabel::InitType::Simple, st::boxTitle) { - _megagroupSetField->setLinkPlaceholder(Messenger::Instance().createInternalLink(qsl("addstickers/"))); + _megagroupSetField->setLinkPlaceholder(Core::App().createInternalLink(qsl("addstickers/"))); _megagroupSetField->setPlaceholderHidden(false); _megagroupSetAddressChangedTimer.setCallback([this] { handleMegagroupSetAddressChange(); }); connect( @@ -804,9 +804,11 @@ const auto origin = Data::FileOriginStickerSet( set->id, set->accessHash); - set->sticker->thumb->load(origin); - auto pix = set->sticker->thumb->pix(origin, set->pixw, set->pixh); - p.drawPixmapLeft(stickerx + (st::contactsPhotoSize - set->pixw) / 2, st::contactsPadding.top() + (st::contactsPhotoSize - set->pixh) / 2, width(), pix); + if (const auto thumb = set->sticker->thumbnail()) { + thumb->load(origin); + auto pix = thumb->pix(origin, set->pixw, set->pixh); + p.drawPixmapLeft(stickerx + (st::contactsPhotoSize - set->pixw) / 2, st::contactsPadding.top() + (st::contactsPhotoSize - set->pixh) / 2, width(), pix); + } } int namex = stickerx + st::contactsPhotoSize + st::contactsPadding.left(); @@ -1575,8 +1577,11 @@ } auto sticker = *outSticker = set.stickers.front(); - auto pixw = sticker->thumb->width(); - auto pixh = sticker->thumb->height(); + const auto size = sticker->thumbnail() + ? sticker->thumbnail()->size() + : QSize(1, 1); + auto pixw = size.width(); + auto pixh = size.height(); if (pixw > st::contactsPhotoSize) { if (pixw > pixh) { pixh = (pixh * st::contactsPhotoSize) / pixw; @@ -1734,7 +1739,10 @@ if (i * _rowHeight < itemsVisibleTop || (i + 1) * _rowHeight > itemsVisibleBottom) { continue; } - if (!_rows[i]->sticker || _rows[i]->sticker->thumb->loaded() || _rows[i]->sticker->loaded()) { + if (!_rows[i]->sticker + || !_rows[i]->sticker->hasThumbnail() + || _rows[i]->sticker->thumbnail()->loaded() + || _rows[i]->sticker->loaded()) { Auth().api().readFeaturedSetDelayed(_rows[i]->id); } } diff -Nru telegram-desktop-1.5.8/Telegram/SourceFiles/boxes/sticker_set_box.cpp telegram-desktop-1.5.11/Telegram/SourceFiles/boxes/sticker_set_box.cpp --- telegram-desktop-1.5.8/Telegram/SourceFiles/boxes/sticker_set_box.cpp 2019-01-21 17:28:45.000000000 +0000 +++ telegram-desktop-1.5.11/Telegram/SourceFiles/boxes/sticker_set_box.cpp 2019-02-01 12:51:46.000000000 +0000 @@ -10,22 +10,21 @@ #include "data/data_document.h" #include "data/data_session.h" #include "lang/lang_keys.h" -#include "mainwidget.h" -#include "mainwindow.h" #include "chat_helpers/stickers.h" #include "boxes/confirm_box.h" -#include "apiwrap.h" -#include "application.h" +#include "core/application.h" #include "storage/localstorage.h" #include "dialogs/dialogs_layout.h" -#include "styles/style_boxes.h" -#include "styles/style_chat_helpers.h" #include "ui/widgets/buttons.h" #include "ui/widgets/scroll_area.h" #include "ui/image/image.h" #include "ui/emoji_config.h" #include "auth_session.h" -#include "messenger.h" +#include "apiwrap.h" +#include "mainwidget.h" +#include "mainwindow.h" +#include "styles/style_boxes.h" +#include "styles/style_chat_helpers.h" namespace { @@ -142,7 +141,7 @@ } void StickerSetBox::shareStickers() { - auto url = Messenger::Instance().createInternalLinkFull(qsl("addstickers/") + _inner->shortName()); + auto url = Core::App().createInternalLinkFull(qsl("addstickers/") + _inner->shortName()); QApplication::clipboard()->setText(url); Ui::show(Box(lang(lng_stickers_copied))); } @@ -201,11 +200,11 @@ auto &v = d.vdocuments.v; _pack.reserve(v.size()); _packOvers.reserve(v.size()); - for (int i = 0, l = v.size(); i < l; ++i) { - auto doc = Auth().data().document(v.at(i)); - if (!doc->sticker()) continue; + for (const auto &item : v) { + const auto document = Auth().data().processDocument(item); + if (!document->sticker()) continue; - _pack.push_back(doc); + _pack.push_back(document); _packOvers.push_back(Animation()); } auto &packs = d.vpacks.v; @@ -473,7 +472,7 @@ p.setOpacity(1); } - doc->checkStickerThumb(); + doc->checkStickerSmall(); float64 coef = qMin((st::stickersSize.width() - st::buttonRadius * 2) / float64(doc->dimensions.width()), (st::stickersSize.height() - st::buttonRadius * 2) / float64(doc->dimensions.height())); if (coef > 1) coef = 1; @@ -481,7 +480,7 @@ if (w < 1) w = 1; if (h < 1) h = 1; QPoint ppos = pos + QPoint((st::stickersSize.width() - w) / 2, (st::stickersSize.height() - h) / 2); - if (const auto image = doc->getStickerThumb()) { + if (const auto image = doc->getStickerSmall()) { p.drawPixmapLeft( ppos, width(), diff -Nru telegram-desktop-1.5.8/Telegram/SourceFiles/boxes/username_box.cpp telegram-desktop-1.5.11/Telegram/SourceFiles/boxes/username_box.cpp --- telegram-desktop-1.5.8/Telegram/SourceFiles/boxes/username_box.cpp 2019-01-21 17:28:45.000000000 +0000 +++ telegram-desktop-1.5.11/Telegram/SourceFiles/boxes/username_box.cpp 2019-02-01 12:51:46.000000000 +0000 @@ -13,8 +13,9 @@ #include "ui/widgets/buttons.h" #include "ui/widgets/input_fields.h" #include "ui/toast/toast.h" -#include "messenger.h" +#include "core/application.h" #include "auth_session.h" +#include "data/data_session.h" #include "data/data_user.h" #include "styles/style_boxes.h" @@ -87,7 +88,7 @@ if (_link->isHidden()) { p.drawTextLeft(st::usernamePadding.left(), linky, width(), lang(lng_username_link_willbe)); p.setPen(st::usernameDefaultFg); - p.drawTextLeft(st::usernamePadding.left(), linky + st::usernameTextStyle.lineHeight + ((st::usernameTextStyle.lineHeight - st::boxTextFont->height) / 2), width(), Messenger::Instance().createInternalLinkFull(qsl("username"))); + p.drawTextLeft(st::usernamePadding.left(), linky + st::usernameTextStyle.lineHeight + ((st::usernameTextStyle.lineHeight - st::boxTextFont->height) / 2), width(), Core::App().createInternalLinkFull(qsl("username"))); } else { p.drawTextLeft(st::usernamePadding.left(), linky, width(), lang(lng_username_link)); } @@ -165,12 +166,12 @@ } void UsernameBox::linkClick() { - QApplication::clipboard()->setText(Messenger::Instance().createInternalLinkFull(getName())); + QApplication::clipboard()->setText(Core::App().createInternalLinkFull(getName())); Ui::Toast::Show(lang(lng_username_copied)); } void UsernameBox::onUpdateDone(const MTPUser &user) { - App::feedUsers(MTP_vector(1, user)); + Auth().data().processUser(user); closeBox(); } @@ -246,7 +247,7 @@ void UsernameBox::updateLinkText() { QString uname = getName(); - _link->setText(st::boxTextFont->elided(Messenger::Instance().createInternalLinkFull(uname), st::boxWidth - st::usernamePadding.left() - st::usernamePadding.right())); + _link->setText(st::boxTextFont->elided(Core::App().createInternalLinkFull(uname), st::boxWidth - st::usernamePadding.left() - st::usernamePadding.right())); if (uname.isEmpty()) { if (!_link->isHidden()) { _link->hide(); diff -Nru telegram-desktop-1.5.8/Telegram/SourceFiles/calls/calls_box_controller.cpp telegram-desktop-1.5.11/Telegram/SourceFiles/calls/calls_box_controller.cpp --- telegram-desktop-1.5.8/Telegram/SourceFiles/calls/calls_box_controller.cpp 2019-01-21 17:28:45.000000000 +0000 +++ telegram-desktop-1.5.11/Telegram/SourceFiles/calls/calls_box_controller.cpp 2019-02-01 12:51:46.000000000 +0000 @@ -255,9 +255,9 @@ )).done([this](const MTPmessages_Messages &result) { _loadRequestId = 0; - auto handleResult = [this](auto &data) { - App::feedUsers(data.vusers); - App::feedChats(data.vchats); + auto handleResult = [&](auto &data) { + Auth().data().processUsers(data.vusers); + Auth().data().processChats(data.vchats); receivedCalls(data.vmessages.v); }; @@ -305,7 +305,7 @@ for (const auto &message : result) { auto msgId = IdFromMessage(message); auto peerId = PeerFromMessage(message); - if (auto peer = App::peerLoaded(peerId)) { + if (auto peer = Auth().data().peerLoaded(peerId)) { auto item = Auth().data().addNewMessage(message, NewMessageExisting); insertRow(item, InsertWay::Append); } else { diff -Nru telegram-desktop-1.5.8/Telegram/SourceFiles/calls/calls_call.cpp telegram-desktop-1.5.11/Telegram/SourceFiles/calls/calls_call.cpp --- telegram-desktop-1.5.8/Telegram/SourceFiles/calls/calls_call.cpp 2019-01-21 17:28:45.000000000 +0000 +++ telegram-desktop-1.5.11/Telegram/SourceFiles/calls/calls_call.cpp 2019-02-01 12:51:46.000000000 +0000 @@ -18,6 +18,7 @@ #include "media/media_audio_track.h" #include "calls/calls_panel.h" #include "data/data_user.h" +#include "data/data_session.h" #ifdef slots #undef slots @@ -201,7 +202,7 @@ setState(State::Waiting); auto &call = result.c_phone_phoneCall(); - App::feedUsers(call.vusers); + Auth().data().processUsers(call.vusers); if (call.vphone_call.type() != mtpc_phoneCallWaiting) { LOG(("Call Error: Expected phoneCallWaiting in response to phone.requestCall()")); finish(FinishType::Failed); @@ -273,7 +274,7 @@ )).done([this](const MTPphone_PhoneCall &result) { Expects(result.type() == mtpc_phone_phoneCall); auto &call = result.c_phone_phoneCall(); - App::feedUsers(call.vusers); + Auth().data().processUsers(call.vusers); if (call.vphone_call.type() != mtpc_phoneCallWaiting) { LOG(("Call Error: Expected phoneCallWaiting in response to phone.acceptCall()")); finish(FinishType::Failed); @@ -487,8 +488,9 @@ MTP_int(tgvoip::VoIPController::GetConnectionMaxLayer())) )).done([this](const MTPphone_PhoneCall &result) { Expects(result.type() == mtpc_phone_phoneCall); + auto &call = result.c_phone_phoneCall(); - App::feedUsers(call.vusers); + Auth().data().processUsers(call.vusers); if (call.vphone_call.type() != mtpc_phoneCall) { LOG(("Call Error: Expected phoneCall in response to phone.confirmCall()")); finish(FinishType::Failed); diff -Nru telegram-desktop-1.5.8/Telegram/SourceFiles/calls/calls_instance.cpp telegram-desktop-1.5.11/Telegram/SourceFiles/calls/calls_instance.cpp --- telegram-desktop-1.5.8/Telegram/SourceFiles/calls/calls_instance.cpp 2019-01-21 17:28:45.000000000 +0000 +++ telegram-desktop-1.5.11/Telegram/SourceFiles/calls/calls_instance.cpp 2019-02-01 12:51:46.000000000 +0000 @@ -8,7 +8,7 @@ #include "calls/calls_instance.h" #include "mtproto/connection.h" -#include "messenger.h" +#include "core/application.h" #include "auth_session.h" #include "apiwrap.h" #include "lang/lang_keys.h" @@ -16,6 +16,7 @@ #include "calls/calls_call.h" #include "calls/calls_panel.h" #include "data/data_user.h" +#include "data/data_session.h" #include "media/media_audio_track.h" #include "platform/platform_specific.h" #include "mainwidget.h" @@ -100,7 +101,7 @@ if (App::quitting()) { LOG(("Calls::Instance doesn't prevent quit any more.")); } - Messenger::Instance().quitPreventFinished(); + Core::App().quitPreventFinished(); } } @@ -222,7 +223,7 @@ void Instance::handleCallUpdate(const MTPPhoneCall &call) { if (call.type() == mtpc_phoneCallRequested) { auto &phoneCall = call.c_phoneCallRequested(); - auto user = App::userLoaded(phoneCall.vadmin_id.v); + auto user = Auth().data().userLoaded(phoneCall.vadmin_id.v); if (!user) { LOG(("API Error: User not loaded for phoneCallRequested.")); } else if (user->isSelf()) { diff -Nru telegram-desktop-1.5.8/Telegram/SourceFiles/calls/calls_panel.cpp telegram-desktop-1.5.11/Telegram/SourceFiles/calls/calls_panel.cpp --- telegram-desktop-1.5.8/Telegram/SourceFiles/calls/calls_panel.cpp 2019-01-21 17:28:45.000000000 +0000 +++ telegram-desktop-1.5.11/Telegram/SourceFiles/calls/calls_panel.cpp 2019-02-01 12:51:46.000000000 +0000 @@ -21,7 +21,7 @@ #include "ui/wrap/fade_wrap.h" #include "ui/empty_userpic.h" #include "ui/emoji_config.h" -#include "messenger.h" +#include "core/application.h" #include "mainwindow.h" #include "lang/lang_keys.h" #include "auth_session.h" @@ -503,34 +503,39 @@ _user->loadUserpic(true); } const auto photo = _user->userpicPhotoId() - ? Auth().data().photo(_user->userpicPhotoId()).get() + ? _user->owner().photo(_user->userpicPhotoId()).get() : nullptr; if (isGoodUserPhoto(photo)) { - photo->full->load(_user->userpicPhotoOrigin(), true); + photo->large()->load(_user->userpicPhotoOrigin(), true); } else if (_user->userpicPhotoUnknown() || (photo && !photo->date)) { - Auth().api().requestFullPeer(_user); + _user->session().api().requestFullPeer(_user); } refreshUserPhoto(); } void Panel::refreshUserPhoto() { const auto photo = _user->userpicPhotoId() - ? Auth().data().photo(_user->userpicPhotoId()).get() + ? _user->owner().photo(_user->userpicPhotoId()).get() : nullptr; const auto isNewPhoto = [&](not_null photo) { - return photo->full->loaded() + return photo->large()->loaded() && (photo->id != _userPhotoId || !_userPhotoFull); }; if (isGoodUserPhoto(photo) && isNewPhoto(photo)) { _userPhotoId = photo->id; _userPhotoFull = true; - createUserpicCache(photo->full, _user->userpicPhotoOrigin()); + createUserpicCache( + photo->isNull() ? nullptr : photo->large().get(), + _user->userpicPhotoOrigin()); } else if (_userPhoto.isNull()) { - createUserpicCache(_user->currentUserpic(), _user->userpicOrigin()); + const auto userpic = _user->currentUserpic(); + createUserpicCache( + userpic ? userpic.get() : nullptr, + _user->userpicOrigin()); } } -void Panel::createUserpicCache(ImagePtr image, Data::FileOrigin origin) { +void Panel::createUserpicCache(Image *image, Data::FileOrigin origin) { auto size = st::callWidth * cIntRetinaFactor(); auto options = _useTransparency ? (Images::Option::RoundedLarge | Images::Option::RoundedTopLeft | Images::Option::RoundedTopRight | Images::Option::Smooth) : Images::Option::None; if (image) { @@ -570,19 +575,19 @@ } bool Panel::isGoodUserPhoto(PhotoData *photo) { - if (!photo || !photo->date) { + if (!photo || photo->isNull()) { return false; } - auto badAspect = [](int a, int b) { + const auto badAspect = [](int a, int b) { return a > 10 * b; }; - auto width = photo->full->width(); - auto height = photo->full->height(); + const auto width = photo->width(); + const auto height = photo->height(); return !badAspect(width, height) && !badAspect(height, width); } void Panel::initGeometry() { - auto center = Messenger::Instance().getPointForCallPanelCenter(); + auto center = Core::App().getPointForCallPanelCenter(); _useTransparency = Platform::TranslucentWindowsSupported(center); setAttribute(Qt::WA_OpaquePaintEvent, !_useTransparency); _padding = _useTransparency ? st::callShadow.extend : style::margins(st::lineWidth, st::lineWidth, st::lineWidth, st::lineWidth); diff -Nru telegram-desktop-1.5.8/Telegram/SourceFiles/calls/calls_panel.h telegram-desktop-1.5.11/Telegram/SourceFiles/calls/calls_panel.h --- telegram-desktop-1.5.8/Telegram/SourceFiles/calls/calls_panel.h 2019-01-21 17:28:45.000000000 +0000 +++ telegram-desktop-1.5.11/Telegram/SourceFiles/calls/calls_panel.h 2019-02-01 12:51:46.000000000 +0000 @@ -92,7 +92,7 @@ void processUserPhoto(); void refreshUserPhoto(); bool isGoodUserPhoto(PhotoData *photo); - void createUserpicCache(ImagePtr image, Data::FileOrigin origin); + void createUserpicCache(Image *image, Data::FileOrigin origin); QRect signalBarsRect() const; void paintSignalBarsBg(Painter &p); diff -Nru telegram-desktop-1.5.8/Telegram/SourceFiles/chat_helpers/emoji_sets_manager.cpp telegram-desktop-1.5.11/Telegram/SourceFiles/chat_helpers/emoji_sets_manager.cpp --- telegram-desktop-1.5.8/Telegram/SourceFiles/chat_helpers/emoji_sets_manager.cpp 2019-01-21 17:28:45.000000000 +0000 +++ telegram-desktop-1.5.11/Telegram/SourceFiles/chat_helpers/emoji_sets_manager.cpp 2019-02-01 12:51:46.000000000 +0000 @@ -17,7 +17,7 @@ #include "lang/lang_keys.h" #include "base/zlib_help.h" #include "layout.h" -#include "messenger.h" +#include "core/application.h" #include "mainwidget.h" #include "styles/style_boxes.h" #include "styles/style_chat_helpers.h" @@ -245,7 +245,7 @@ , _id(id) , _size(GetDownloadSize(_id)) , _state(Loading{ 0, _size }) -, _mtproto(Messenger::Instance().mtp()) { +, _mtproto(Core::App().mtp()) { const auto ready = [=](std::unique_ptr loader) { if (loader) { setImplementation(std::move(loader)); diff -Nru telegram-desktop-1.5.8/Telegram/SourceFiles/chat_helpers/field_autocomplete.cpp telegram-desktop-1.5.11/Telegram/SourceFiles/chat_helpers/field_autocomplete.cpp --- telegram-desktop-1.5.8/Telegram/SourceFiles/chat_helpers/field_autocomplete.cpp 2019-01-21 17:28:45.000000000 +0000 +++ telegram-desktop-1.5.11/Telegram/SourceFiles/chat_helpers/field_autocomplete.cpp 2019-02-01 12:51:46.000000000 +0000 @@ -561,7 +561,7 @@ App::roundRect(p, QRect(tl, st::stickerPanSize), st::emojiPanHover, StickerHoverCorners); } - document->checkStickerThumb(); + document->checkStickerSmall(); float64 coef = qMin((st::stickerPanSize.width() - st::buttonRadius * 2) / float64(document->dimensions.width()), (st::stickerPanSize.height() - st::buttonRadius * 2) / float64(document->dimensions.height())); if (coef > 1) coef = 1; @@ -569,7 +569,7 @@ if (w < 1) w = 1; if (h < 1) h = 1; QPoint ppos = pos + QPoint((st::stickerPanSize.width() - w) / 2, (st::stickerPanSize.height() - h) / 2); - if (const auto image = document->getStickerThumb()) { + if (const auto image = document->getStickerSmall()) { p.drawPixmapLeft(ppos, width(), image->pix(document->stickerSetOrigin(), w, h)); } } diff -Nru telegram-desktop-1.5.8/Telegram/SourceFiles/chat_helpers/gifs_list_widget.cpp telegram-desktop-1.5.11/Telegram/SourceFiles/chat_helpers/gifs_list_widget.cpp --- telegram-desktop-1.5.8/Telegram/SourceFiles/chat_helpers/gifs_list_widget.cpp 2019-01-21 17:28:45.000000000 +0000 +++ telegram-desktop-1.5.11/Telegram/SourceFiles/chat_helpers/gifs_list_widget.cpp 2019-02-01 12:51:46.000000000 +0000 @@ -223,7 +223,7 @@ auto adding = (it != _inlineCache.cend()); if (result.type() == mtpc_messages_botResults) { auto &d = result.c_messages_botResults(); - App::feedUsers(d.vusers); + Auth().data().processUsers(d.vusers); auto &v = d.vresults.v; auto queryId = d.vquery_id.v; @@ -352,11 +352,10 @@ auto item = _rows[row].items[column]; if (const auto photo = item->getPhoto()) { - if (photo->medium->loaded() || photo->thumb->loaded()) { + if (photo->thumbnail()->loaded()) { _photoChosen.fire_copy(photo); - } else if (!photo->medium->loading()) { - photo->thumb->loadEvenCancelled(Data::FileOrigin()); - photo->medium->loadEvenCancelled(Data::FileOrigin()); + } else if (!photo->thumbnail()->loading()) { + photo->thumbnail()->loadEvenCancelled(Data::FileOrigin()); } } else if (const auto document = item->getDocument()) { if (document->loaded()) { @@ -842,12 +841,15 @@ if (!_searchBot && !_searchBotRequestId) { auto username = str_const_toString(kSearchBotUsername); - _searchBotRequestId = request(MTPcontacts_ResolveUsername(MTP_string(username))).done([this](const MTPcontacts_ResolvedPeer &result) { + _searchBotRequestId = request(MTPcontacts_ResolveUsername( + MTP_string(username) + )).done([=](const MTPcontacts_ResolvedPeer &result) { Expects(result.type() == mtpc_contacts_resolvedPeer); + auto &data = result.c_contacts_resolvedPeer(); - App::feedUsers(data.vusers); - App::feedChats(data.vchats); - if (auto peer = App::peerLoaded(peerFromMTP(data.vpeer))) { + Auth().data().processUsers(data.vusers); + Auth().data().processChats(data.vchats); + if (auto peer = Auth().data().peerLoaded(peerFromMTP(data.vpeer))) { if (auto user = peer->asUser()) { _searchBot = user; } diff -Nru telegram-desktop-1.5.8/Telegram/SourceFiles/chat_helpers/stickers.cpp telegram-desktop-1.5.11/Telegram/SourceFiles/chat_helpers/stickers.cpp --- telegram-desktop-1.5.8/Telegram/SourceFiles/chat_helpers/stickers.cpp 2019-01-21 17:28:45.000000000 +0000 +++ telegram-desktop-1.5.11/Telegram/SourceFiles/chat_helpers/stickers.cpp 2019-02-01 12:51:46.000000000 +0000 @@ -480,9 +480,9 @@ auto custom = sets.find(CustomSetId); auto pack = Pack(); pack.reserve(items.size()); - for_const (auto &mtpDocument, items) { + for (const auto &item : items) { ++dateIndex; - auto document = Auth().data().document(mtpDocument); + const auto document = Auth().data().processDocument(item); if (!document->sticker()) { continue; } @@ -662,10 +662,11 @@ saved.clear(); saved.reserve(items.size()); - for_const (auto &gif, items) { - auto document = Auth().data().document(gif); + for (const auto &item : items) { + const auto document = Auth().data().processDocument(item); if (!document->isGifv()) { - LOG(("API Error: bad document returned in HistoryWidget::savedGifsGot!")); + LOG(("API Error: " + "bad document returned in HistoryWidget::savedGifsGot!")); continue; } @@ -917,13 +918,13 @@ auto pack = Pack(); pack.reserve(d_docs.size()); - for (auto i = 0, l = d_docs.size(); i != l; ++i) { - auto doc = Auth().data().document(d_docs.at(i)); - if (!doc->sticker()) continue; + for (const auto &item : d_docs) { + const auto document = Auth().data().processDocument(item); + if (!document->sticker()) continue; - pack.push_back(doc); + pack.push_back(document); if (custom != sets.cend()) { - auto index = custom->stickers.indexOf(doc); + const auto index = custom->stickers.indexOf(document); if (index >= 0) { custom->stickers.removeAt(index); } diff -Nru telegram-desktop-1.5.8/Telegram/SourceFiles/chat_helpers/stickers_list_widget.cpp telegram-desktop-1.5.11/Telegram/SourceFiles/chat_helpers/stickers_list_widget.cpp --- telegram-desktop-1.5.8/Telegram/SourceFiles/chat_helpers/stickers_list_widget.cpp 2019-01-21 17:28:45.000000000 +0000 +++ telegram-desktop-1.5.11/Telegram/SourceFiles/chat_helpers/stickers_list_widget.cpp 2019-02-01 12:51:46.000000000 +0000 @@ -259,8 +259,8 @@ void StickersListWidget::Footer::preloadImages() { enumerateVisibleIcons([](const StickerIcon &icon, int x) { - if (auto sticker = icon.sticker) { - sticker->thumb->load(sticker->stickerSetOrigin()); + if (const auto sticker = icon.sticker) { + sticker->loadThumbnail(sticker->stickerSetOrigin()); } }); } @@ -631,10 +631,12 @@ int x) const { if (icon.sticker) { const auto origin = icon.sticker->stickerSetOrigin(); - icon.sticker->thumb->load(origin); - auto pix = icon.sticker->thumb->pix(origin, icon.pixw, icon.pixh); + if (const auto thumb = icon.sticker->thumbnail()) { + thumb->load(origin); + auto pix = thumb->pix(origin, icon.pixw, icon.pixh); - p.drawPixmapLeft(x + (st::stickerIconWidth - icon.pixw) / 2, _iconsTop + (st::emojiFooterHeight - icon.pixh) / 2, width(), pix); + p.drawPixmapLeft(x + (st::stickerIconWidth - icon.pixw) / 2, _iconsTop + (st::emojiFooterHeight - icon.pixh) / 2, width(), pix); + } } else if (icon.megagroup) { icon.megagroup->paintUserpicLeft(p, x + (st::stickerIconWidth - st::stickerGroupCategorySize) / 2, _iconsTop + (st::emojiFooterHeight - st::stickerGroupCategorySize) / 2, width(), st::stickerGroupCategorySize); } else { @@ -753,7 +755,9 @@ int count = qMin(set.pack.size(), _columnCount); int loaded = 0; for (int j = 0; j < count; ++j) { - if (set.pack[j]->thumb->loaded() || set.pack[j]->loaded()) { + if (!set.pack[j]->hasThumbnail() + || set.pack[j]->thumbnail()->loaded() + || set.pack[j]->loaded()) { ++loaded; } } @@ -1092,7 +1096,7 @@ setData = &d.vset.c_stickerSet(); } for (const auto &cover : d.vcovers.v) { - const auto document = Auth().data().document(cover); + const auto document = Auth().data().processDocument(cover); if (document->sticker()) { covers.push_back(document); } @@ -1339,14 +1343,14 @@ App::roundRect(p, QRect(tl, _singleSize), st::emojiPanHover, StickerHoverCorners); } - document->checkStickerThumb(); + document->checkStickerSmall(); auto coef = qMin((_singleSize.width() - st::buttonRadius * 2) / float64(document->dimensions.width()), (_singleSize.height() - st::buttonRadius * 2) / float64(document->dimensions.height())); if (coef > 1) coef = 1; auto w = qMax(qRound(coef * document->dimensions.width()), 1); auto h = qMax(qRound(coef * document->dimensions.height()), 1); auto ppos = pos + QPoint((_singleSize.width() - w) / 2, (_singleSize.height() - h) / 2); - if (const auto image = document->getStickerThumb()) { + if (const auto image = document->getStickerSmall()) { if (image->loaded()) { p.drawPixmapLeft( ppos, @@ -1786,7 +1790,7 @@ const auto document = sets[i].pack[j]; if (!document || !document->sticker()) continue; - document->checkStickerThumb(); + document->checkStickerSmall(); } if (k > _columnCount * (_columnCount + 1)) break; } @@ -2047,7 +2051,10 @@ } auto s = _mySets[i].pack[0]; auto availw = st::stickerIconWidth - 2 * st::stickerIconPadding, availh = st::emojiFooterHeight - 2 * st::stickerIconPadding; - auto thumbw = s->thumb->width(), thumbh = s->thumb->height(), pixw = 1, pixh = 1; + const auto size = s->hasThumbnail() + ? s->thumbnail()->size() + : QSize(); + auto thumbw = size.width(), thumbh = size.height(), pixw = 1, pixh = 1; if (availw * thumbh > availh * thumbw) { pixh = availh; pixw = (pixh * thumbw) / thumbh; diff -Nru telegram-desktop-1.5.8/Telegram/SourceFiles/chat_helpers/tabbed_panel.cpp telegram-desktop-1.5.11/Telegram/SourceFiles/chat_helpers/tabbed_panel.cpp --- telegram-desktop-1.5.8/Telegram/SourceFiles/chat_helpers/tabbed_panel.cpp 2019-01-21 17:28:45.000000000 +0000 +++ telegram-desktop-1.5.11/Telegram/SourceFiles/chat_helpers/tabbed_panel.cpp 2019-02-01 12:51:46.000000000 +0000 @@ -12,7 +12,7 @@ #include "chat_helpers/tabbed_selector.h" #include "window/window_controller.h" #include "mainwindow.h" -#include "messenger.h" +#include "core/application.h" #include "styles/style_chat_helpers.h" namespace ChatHelpers { @@ -192,7 +192,7 @@ } void TabbedPanel::enterEventHook(QEvent *e) { - Messenger::Instance().registerLeaveSubscription(this); + Core::App().registerLeaveSubscription(this); showAnimated(); } @@ -204,7 +204,7 @@ } void TabbedPanel::leaveEventHook(QEvent *e) { - Messenger::Instance().unregisterLeaveSubscription(this); + Core::App().unregisterLeaveSubscription(this); if (preventAutoHide()) { return; } diff -Nru telegram-desktop-1.5.8/Telegram/SourceFiles/config.h telegram-desktop-1.5.11/Telegram/SourceFiles/config.h --- telegram-desktop-1.5.8/Telegram/SourceFiles/config.h 2019-01-21 17:28:45.000000000 +0000 +++ telegram-desktop-1.5.11/Telegram/SourceFiles/config.h 2019-02-01 12:51:46.000000000 +0000 @@ -17,15 +17,6 @@ constexpr str_const AppFile = "Telegram"; enum { - MTPIdsBufferSize = 400, // received msgIds and wereAcked msgIds count stored - MTPCheckResendTimeout = 10000, // how much time passed from send till we resend request or check it's state, in ms - MTPCheckResendWaiting = 1000, // how much time to wait for some more requests, when resending request or checking it's state, in ms - MTPAckSendWaiting = 10000, // how much time to wait for some more requests, when sending msg acks - MTPResendThreshold = 1, // how much ints should message contain for us not to resend, but to check it's state - MTPContainerLives = 600, // container lives 10 minutes in haveSent map - - MTPKillFileSessionTimeout = 5000, // how much time without upload / download causes additional session kill - MaxSelectedItems = 100, MaxPhoneCodeLength = 4, // max length of country phone code @@ -71,8 +62,6 @@ MaxMessageSize = 4096, - WriteMapTimeout = 1000, - SetOnlineAfterActivity = 30, // user with hidden last seen stays online for such amount of seconds in the interface ServiceUserId = 777000, diff -Nru telegram-desktop-1.5.8/Telegram/SourceFiles/core/application.cpp telegram-desktop-1.5.11/Telegram/SourceFiles/core/application.cpp --- telegram-desktop-1.5.8/Telegram/SourceFiles/core/application.cpp 1970-01-01 00:00:00.000000000 +0000 +++ telegram-desktop-1.5.11/Telegram/SourceFiles/core/application.cpp 2019-02-01 12:51:46.000000000 +0000 @@ -0,0 +1,1145 @@ +/* +This file is part of Telegram Desktop, +the official desktop application for the Telegram messaging service. + +For license and copyright information please follow this link: +https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL +*/ +#include "core/application.h" + +#include "data/data_photo.h" +#include "data/data_document.h" +#include "data/data_session.h" +#include "data/data_user.h" +#include "base/timer.h" +#include "core/update_checker.h" +#include "core/shortcuts.h" +#include "core/sandbox.h" +#include "core/local_url_handlers.h" +#include "core/launcher.h" +#include "storage/localstorage.h" +#include "platform/platform_specific.h" +#include "mainwindow.h" +#include "dialogs/dialogs_entry.h" +#include "history/history.h" +#include "auth_session.h" +#include "apiwrap.h" +#include "calls/calls_instance.h" +#include "lang/lang_file_parser.h" +#include "lang/lang_translator.h" +#include "lang/lang_cloud_manager.h" +#include "lang/lang_hardcoded.h" +#include "observer_peer.h" +#include "storage/storage_databases.h" +#include "mainwidget.h" +#include "mediaview.h" +#include "mtproto/dc_options.h" +#include "mtproto/mtp_instance.h" +#include "media/player/media_player_instance.h" +#include "media/media_audio.h" +#include "media/media_audio_track.h" +#include "window/notifications_manager.h" +#include "window/themes/window_theme.h" +#include "window/window_lock_widgets.h" +#include "history/history_location_manager.h" +#include "ui/widgets/tooltip.h" +#include "ui/image/image.h" +#include "ui/text_options.h" +#include "ui/emoji_config.h" +#include "storage/serialize_common.h" +#include "window/window_controller.h" +#include "base/qthelp_regex.h" +#include "base/qthelp_url.h" +#include "boxes/connection_box.h" +#include "boxes/confirm_phone_box.h" +#include "boxes/confirm_box.h" +#include "boxes/share_box.h" + +namespace Core { +namespace { + +constexpr auto kQuitPreventTimeoutMs = 1500; + +} // namespace + +struct Application::Private { + UserId authSessionUserId = 0; + QByteArray authSessionUserSerialized; + int32 authSessionUserStreamVersion = 0; + std::unique_ptr storedAuthSession; + MTP::Instance::Config mtpConfig; + MTP::AuthKeysList mtpKeysToDestroy; + base::Timer quitTimer; +}; + +Application::Application(not_null launcher) +: QObject() +, _launcher(launcher) +, _private(std::make_unique()) +, _databases(std::make_unique()) +, _langpack(std::make_unique()) +, _audio(std::make_unique()) +, _logo(Window::LoadLogo()) +, _logoNoMargin(Window::LoadLogoNoMargin()) { + Expects(!_logo.isNull()); + Expects(!_logoNoMargin.isNull()); +} + +void Application::run() { + Fonts::Start(); + + ThirdParty::start(); + Global::start(); + refreshGlobalProxy(); // Depends on Global::started(). + + startLocalStorage(); + + if (Local::oldSettingsVersion() < AppVersion) { + psNewVersion(); + } + + if (cLaunchMode() == LaunchModeAutoStart && !cAutoStart()) { + psAutoStart(false, true); + App::quit(); + return; + } + + _translator = std::make_unique(); + QCoreApplication::instance()->installTranslator(_translator.get()); + + style::startManager(); + anim::startManager(); + Ui::InitTextOptions(); + Ui::Emoji::Init(); + Media::Player::start(_audio.get()); + + DEBUG_LOG(("Application Info: inited...")); + + QCoreApplication::instance()->installNativeEventFilter( + psNativeEventFilter()); + + cChangeTimeFormat(QLocale::system().timeFormat(QLocale::ShortFormat)); + + DEBUG_LOG(("Application Info: starting app...")); + + // Create mime database, so it won't be slow later. + QMimeDatabase().mimeTypeForName(qsl("text/plain")); + + _window = std::make_unique(); + _window->init(); + + auto currentGeometry = _window->geometry(); + _mediaView = std::make_unique(); + _window->setGeometry(currentGeometry); + + QCoreApplication::instance()->installEventFilter(this); + connect( + static_cast(QCoreApplication::instance()), + &QGuiApplication::applicationStateChanged, + this, + &Application::stateChanged); + + DEBUG_LOG(("Application Info: window created...")); + + startShortcuts(); + App::initMedia(); + + Local::ReadMapState state = Local::readMap(QByteArray()); + if (state == Local::ReadMapPassNeeded) { + Global::SetLocalPasscode(true); + Global::RefLocalPasscodeChanged().notify(); + lockByPasscode(); + DEBUG_LOG(("Application Info: passcode needed...")); + } else { + DEBUG_LOG(("Application Info: local map read...")); + startMtp(); + DEBUG_LOG(("Application Info: MTP started...")); + if (AuthSession::Exists()) { + _window->setupMain(); + } else { + _window->setupIntro(); + } + } + DEBUG_LOG(("Application Info: showing.")); + _window->firstShow(); + + if (cStartToSettings()) { + _window->showSettings(); + } + + _window->updateIsActive(Global::OnlineFocusTimeout()); + + for (const auto &error : Shortcuts::Errors()) { + LOG(("Shortcuts Error: %1").arg(error)); + } +} + +bool Application::hideMediaView() { + if (_mediaView && !_mediaView->isHidden()) { + _mediaView->hide(); + if (auto activeWindow = getActiveWindow()) { + activeWindow->reActivateWindow(); + } + return true; + } + return false; +} + +void Application::showPhoto(not_null link) { + const auto item = App::histItemById(link->context()); + const auto peer = link->peer(); + return (!item && peer) + ? showPhoto(link->photo(), peer) + : showPhoto(link->photo(), item); +} + +void Application::showPhoto(not_null photo, HistoryItem *item) { + _mediaView->showPhoto(photo, item); + _mediaView->activateWindow(); + _mediaView->setFocus(); +} + +void Application::showPhoto( + not_null photo, + not_null peer) { + _mediaView->showPhoto(photo, peer); + _mediaView->activateWindow(); + _mediaView->setFocus(); +} + +void Application::showDocument(not_null document, HistoryItem *item) { + if (cUseExternalVideoPlayer() && document->isVideoFile()) { + QDesktopServices::openUrl(QUrl("file:///" + document->location(false).fname)); + } else { + _mediaView->showDocument(document, item); + _mediaView->activateWindow(); + _mediaView->setFocus(); + } +} + +PeerData *Application::ui_getPeerForMouseAction() { + if (_mediaView && !_mediaView->isHidden()) { + return _mediaView->ui_getPeerForMouseAction(); + } else if (auto main = App::main()) { + return main->ui_getPeerForMouseAction(); + } + return nullptr; +} + +bool Application::eventFilter(QObject *object, QEvent *e) { + switch (e->type()) { + case QEvent::KeyPress: + case QEvent::MouseButtonPress: + case QEvent::TouchBegin: + case QEvent::Wheel: { + psUserActionDone(); + } break; + + case QEvent::ShortcutOverride: { + // handle shortcuts ourselves + return true; + } break; + + case QEvent::Shortcut: { + const auto event = static_cast(e); + DEBUG_LOG(("Shortcut event caught: %1" + ).arg(event->key().toString())); + if (Shortcuts::HandleEvent(event)) { + return true; + } + } break; + + case QEvent::ApplicationActivate: { + if (object == QCoreApplication::instance()) { + psUserActionDone(); + } + } break; + + case QEvent::FileOpen: { + if (object == QCoreApplication::instance()) { + const auto event = static_cast(e); + const auto url = QString::fromUtf8( + event->url().toEncoded().trimmed()); + if (url.startsWith(qstr("tg://"), Qt::CaseInsensitive)) { + cSetStartUrl(url.mid(0, 8192)); + checkStartUrl(); + } + if (StartUrlRequiresActivate(url)) { + _window->activate(); + } + } + } break; + } + + return QObject::eventFilter(object, e); +} + +void Application::setCurrentProxy( + const ProxyData &proxy, + ProxyData::Settings settings) { + const auto key = [&](const ProxyData &proxy) { + if (proxy.type == ProxyData::Type::Mtproto) { + return std::make_pair(proxy.host, proxy.port); + } + return std::make_pair(QString(), uint32(0)); + }; + const auto previousKey = key( + (Global::ProxySettings() == ProxyData::Settings::Enabled + ? Global::SelectedProxy() + : ProxyData())); + Global::SetSelectedProxy(proxy); + Global::SetProxySettings(settings); + refreshGlobalProxy(); + if (_mtproto) { + _mtproto->restart(); + if (previousKey != key(proxy)) { + _mtproto->reInitConnection(_mtproto->mainDcId()); + } + } + if (_mtprotoForKeysDestroy) { + _mtprotoForKeysDestroy->restart(); + } + Global::RefConnectionTypeChanged().notify(); +} + +void Application::badMtprotoConfigurationError() { + if (Global::ProxySettings() == ProxyData::Settings::Enabled + && !_badProxyDisableBox) { + const auto disableCallback = [=] { + setCurrentProxy( + Global::SelectedProxy(), + ProxyData::Settings::System); + }; + _badProxyDisableBox = Ui::show(Box( + Lang::Hard::ProxyConfigError(), + disableCallback)); + } +} + +void Application::setMtpMainDcId(MTP::DcId mainDcId) { + Expects(!_mtproto); + + _private->mtpConfig.mainDcId = mainDcId; +} + +void Application::setMtpKey(MTP::DcId dcId, const MTP::AuthKey::Data &keyData) { + Expects(!_mtproto); + + _private->mtpConfig.keys.push_back(std::make_shared(MTP::AuthKey::Type::ReadFromFile, dcId, keyData)); +} + +QByteArray Application::serializeMtpAuthorization() const { + auto serialize = [this](auto mainDcId, auto &keys, auto &keysToDestroy) { + auto keysSize = [](auto &list) { + return sizeof(qint32) + list.size() * (sizeof(qint32) + MTP::AuthKey::Data().size()); + }; + auto writeKeys = [](QDataStream &stream, auto &keys) { + stream << qint32(keys.size()); + for (auto &key : keys) { + stream << qint32(key->dcId()); + key->write(stream); + } + }; + + auto result = QByteArray(); + auto size = sizeof(qint32) + sizeof(qint32); // userId + mainDcId + size += keysSize(keys) + keysSize(keysToDestroy); + result.reserve(size); + { + QDataStream stream(&result, QIODevice::WriteOnly); + stream.setVersion(QDataStream::Qt_5_1); + + auto currentUserId = _authSession ? _authSession->userId() : 0; + stream << qint32(currentUserId) << qint32(mainDcId); + writeKeys(stream, keys); + writeKeys(stream, keysToDestroy); + + DEBUG_LOG(("MTP Info: Keys written, userId: %1, dcId: %2").arg(currentUserId).arg(mainDcId)); + } + return result; + }; + if (_mtproto) { + auto keys = _mtproto->getKeysForWrite(); + auto keysToDestroy = _mtprotoForKeysDestroy ? _mtprotoForKeysDestroy->getKeysForWrite() : MTP::AuthKeysList(); + return serialize(_mtproto->mainDcId(), keys, keysToDestroy); + } + auto &keys = _private->mtpConfig.keys; + auto &keysToDestroy = _private->mtpKeysToDestroy; + return serialize(_private->mtpConfig.mainDcId, keys, keysToDestroy); +} + +void Application::setAuthSessionUserId(UserId userId) { + Expects(!authSession()); + + _private->authSessionUserId = userId; +} + +void Application::setAuthSessionFromStorage( + std::unique_ptr data, + QByteArray &&selfSerialized, + int32 selfStreamVersion) { + Expects(!authSession()); + + DEBUG_LOG(("authSessionUserSerialized set: %1" + ).arg(selfSerialized.size())); + + _private->storedAuthSession = std::move(data); + _private->authSessionUserSerialized = std::move(selfSerialized); + _private->authSessionUserStreamVersion = selfStreamVersion; +} + +AuthSessionSettings *Application::getAuthSessionSettings() { + if (_private->authSessionUserId) { + return _private->storedAuthSession + ? _private->storedAuthSession.get() + : nullptr; + } else if (_authSession) { + return &_authSession->settings(); + } + return nullptr; +} + +void Application::setMtpAuthorization(const QByteArray &serialized) { + Expects(!_mtproto); + + QDataStream stream(serialized); + stream.setVersion(QDataStream::Qt_5_1); + + auto userId = Serialize::read(stream); + auto mainDcId = Serialize::read(stream); + if (stream.status() != QDataStream::Ok) { + LOG(("MTP Error: could not read main fields from serialized mtp authorization.")); + return; + } + + setAuthSessionUserId(userId); + _private->mtpConfig.mainDcId = mainDcId; + + auto readKeys = [&stream](auto &keys) { + auto count = Serialize::read(stream); + if (stream.status() != QDataStream::Ok) { + LOG(("MTP Error: could not read keys count from serialized mtp authorization.")); + return; + } + keys.reserve(count); + for (auto i = 0; i != count; ++i) { + auto dcId = Serialize::read(stream); + auto keyData = Serialize::read(stream); + if (stream.status() != QDataStream::Ok) { + LOG(("MTP Error: could not read key from serialized mtp authorization.")); + return; + } + keys.push_back(std::make_shared(MTP::AuthKey::Type::ReadFromFile, dcId, keyData)); + } + }; + readKeys(_private->mtpConfig.keys); + readKeys(_private->mtpKeysToDestroy); + LOG(("MTP Info: read keys, current: %1, to destroy: %2").arg(_private->mtpConfig.keys.size()).arg(_private->mtpKeysToDestroy.size())); +} + +void Application::startMtp() { + Expects(!_mtproto); + + auto config = base::take(_private->mtpConfig); + config.deviceModel = _launcher->deviceModel(); + config.systemVersion = _launcher->systemVersion(); + _mtproto = std::make_unique( + _dcOptions.get(), + MTP::Instance::Mode::Normal, + std::move(config)); + _mtproto->setUserPhone(cLoggedPhoneNumber()); + _private->mtpConfig.mainDcId = _mtproto->mainDcId(); + + _mtproto->setStateChangedHandler([](MTP::ShiftedDcId dc, int32 state) { + if (dc == MTP::maindc()) { + Global::RefConnectionTypeChanged().notify(); + } + }); + _mtproto->setSessionResetHandler([](MTP::ShiftedDcId shiftedDcId) { + if (App::main() && shiftedDcId == MTP::maindc()) { + App::main()->getDifference(); + } + }); + + if (!_private->mtpKeysToDestroy.empty()) { + destroyMtpKeys(base::take(_private->mtpKeysToDestroy)); + } + + if (_private->authSessionUserId) { + DEBUG_LOG(("authSessionUserSerialized.size: %1" + ).arg(_private->authSessionUserSerialized.size())); + QDataStream peekStream(_private->authSessionUserSerialized); + const auto phone = Serialize::peekUserPhone( + _private->authSessionUserStreamVersion, + peekStream); + const auto flags = MTPDuser::Flag::f_self | (phone.isEmpty() + ? MTPDuser::Flag() + : MTPDuser::Flag::f_phone); + authSessionCreate(MTP_user( + MTP_flags(flags), + MTP_int(base::take(_private->authSessionUserId)), + MTPlong(), // access_hash + MTPstring(), // first_name + MTPstring(), // last_name + MTPstring(), // username + MTP_string(phone), + MTPUserProfilePhoto(), + MTPUserStatus(), + MTPint(), // bot_info_version + MTPstring(), // restriction_reason + MTPstring(), // bot_inline_placeholder + MTPstring())); // lang_code + Local::readSelf( + base::take(_private->authSessionUserSerialized), + base::take(_private->authSessionUserStreamVersion)); + } + if (_private->storedAuthSession) { + if (_authSession) { + _authSession->moveSettingsFrom( + std::move(*_private->storedAuthSession)); + } + _private->storedAuthSession.reset(); + } + + _langCloudManager = std::make_unique( + langpack(), + mtp()); + if (!UpdaterDisabled()) { + UpdateChecker().setMtproto(mtp()); + } + + if (_authSession) { + // Skip all pending self updates so that we won't Local::writeSelf. + Notify::peerUpdatedSendDelayed(); + + Media::Player::mixer()->setVoicePlaybackDoubled( + Global::VoiceMsgPlaybackDoubled()); + } +} + +void Application::destroyMtpKeys(MTP::AuthKeysList &&keys) { + if (keys.empty()) { + return; + } + if (_mtprotoForKeysDestroy) { + _mtprotoForKeysDestroy->addKeysForDestroy(std::move(keys)); + Local::writeMtpData(); + return; + } + auto destroyConfig = MTP::Instance::Config(); + destroyConfig.mainDcId = MTP::Instance::Config::kNoneMainDc; + destroyConfig.keys = std::move(keys); + destroyConfig.deviceModel = _launcher->deviceModel(); + destroyConfig.systemVersion = _launcher->systemVersion(); + _mtprotoForKeysDestroy = std::make_unique( + _dcOptions.get(), + MTP::Instance::Mode::KeysDestroyer, + std::move(destroyConfig)); + connect( + _mtprotoForKeysDestroy.get(), + &MTP::Instance::allKeysDestroyed, + [=] { allKeysDestroyed(); }); +} + +void Application::allKeysDestroyed() { + LOG(("MTP Info: all keys scheduled for destroy are destroyed.")); + crl::on_main(this, [=] { + _mtprotoForKeysDestroy = nullptr; + Local::writeMtpData(); + }); +} + +void Application::suggestMainDcId(MTP::DcId mainDcId) { + Assert(_mtproto != nullptr); + + _mtproto->suggestMainDcId(mainDcId); + if (_private->mtpConfig.mainDcId != MTP::Instance::Config::kNotSetMainDc) { + _private->mtpConfig.mainDcId = mainDcId; + } +} + +void Application::destroyStaleAuthorizationKeys() { + Assert(_mtproto != nullptr); + + for (const auto &key : _mtproto->getKeysForWrite()) { + // Disable this for now. + if (key->type() == MTP::AuthKey::Type::ReadFromFile) { + _private->mtpKeysToDestroy = _mtproto->getKeysForWrite(); + LOG(("MTP Info: destroying stale keys, count: %1" + ).arg(_private->mtpKeysToDestroy.size())); + resetAuthorizationKeys(); + return; + } + } +} + +void Application::resetAuthorizationKeys() { + _mtproto = nullptr; + startMtp(); + Local::writeMtpData(); +} + +void Application::startLocalStorage() { + _dcOptions = std::make_unique(); + _dcOptions->constructFromBuiltIn(); + Local::start(); + subscribe(_dcOptions->changed(), [this](const MTP::DcOptions::Ids &ids) { + Local::writeSettings(); + if (auto instance = mtp()) { + for (auto id : ids) { + instance->restart(id); + } + } + }); + subscribe(authSessionChanged(), [=] { + InvokeQueued(this, [=] { + const auto phone = AuthSession::Exists() + ? Auth().user()->phone() + : QString(); + if (cLoggedPhoneNumber() != phone) { + cSetLoggedPhoneNumber(phone); + if (_mtproto) { + _mtproto->setUserPhone(phone); + } + Local::writeSettings(); + } + if (_mtproto) { + _mtproto->requestConfig(); + } + Platform::SetApplicationIcon(Window::CreateIcon()); + Shortcuts::ToggleSupportShortcuts( + _authSession && _authSession->supportMode()); + }); + }); +} + +void Application::forceLogOut(const TextWithEntities &explanation) { + const auto box = Ui::show(Box( + explanation, + lang(lng_passcode_logout))); + box->setCloseByEscape(false); + box->setCloseByOutsideClick(false); + connect(box, &QObject::destroyed, [=] { + crl::on_main(this, [=] { + if (AuthSession::Exists()) { + resetAuthorizationKeys(); + loggedOut(); + } + }); + }); +} + +void Application::checkLocalTime() { + const auto updated = checkms(); + if (App::main()) App::main()->checkLastUpdate(updated); +} + +void Application::stateChanged(Qt::ApplicationState state) { + if (state == Qt::ApplicationActive) { + handleAppActivated(); + } else { + handleAppDeactivated(); + } +} + +void Application::handleAppActivated() { + checkLocalTime(); + if (_window) { + _window->updateIsActive(Global::OnlineFocusTimeout()); + } +} + +void Application::handleAppDeactivated() { + if (_window) { + _window->updateIsActive(Global::OfflineBlurTimeout()); + } + Ui::Tooltip::Hide(); +} + +void Application::call_handleUnreadCounterUpdate() { + Global::RefUnreadCounterUpdate().notify(true); +} + +void Application::call_handleDelayedPeerUpdates() { + Notify::peerUpdatedSendDelayed(); +} + +void Application::call_handleObservables() { + base::HandleObservables(); +} + +void Application::switchDebugMode() { + if (Logs::DebugEnabled()) { + Logs::SetDebugEnabled(false); + _launcher->writeDebugModeSetting(); + App::restart(); + } else { + Logs::SetDebugEnabled(true); + _launcher->writeDebugModeSetting(); + DEBUG_LOG(("Debug logs started.")); + Ui::hideLayer(); + } +} + +void Application::switchWorkMode() { + Global::SetDialogsModeEnabled(!Global::DialogsModeEnabled()); + Global::SetDialogsMode(Dialogs::Mode::All); + Local::writeUserSettings(); + App::restart(); +} + +void Application::switchTestMode() { + if (cTestMode()) { + QFile(cWorkingDir() + qsl("tdata/withtestmode")).remove(); + cSetTestMode(false); + } else { + QFile f(cWorkingDir() + qsl("tdata/withtestmode")); + if (f.open(QIODevice::WriteOnly)) { + f.write("1"); + f.close(); + } + cSetTestMode(true); + } + App::restart(); +} + +void Application::writeInstallBetaVersionsSetting() { + _launcher->writeInstallBetaVersionsSetting(); +} + +void Application::authSessionCreate(const MTPUser &user) { + Expects(_mtproto != nullptr); + + _authSession = std::make_unique(user); + _mtproto->setUpdatesHandler(::rpcDone([]( + const mtpPrime *from, + const mtpPrime *end) { + if (const auto main = App::main()) { + main->updateReceived(from, end); + } + })); + _mtproto->setGlobalFailHandler(::rpcFail([=](const RPCError &error) { + crl::on_main(_authSession.get(), [=] { logOut(); }); + return true; + })); + authSessionChanged().notify(true); +} + +void Application::authSessionDestroy() { + _private->storedAuthSession.reset(); + _private->authSessionUserId = 0; + _private->authSessionUserSerialized = {}; + if (_authSession) { + unlockTerms(); + _mtproto->clearGlobalHandlers(); + _authSession = nullptr; + authSessionChanged().notify(true); + Notify::unreadCounterUpdated(); + } +} + +int Application::unreadBadge() const { + return _authSession ? _authSession->data().unreadBadge() : 0; +} + +bool Application::unreadBadgeMuted() const { + return _authSession ? _authSession->data().unreadBadgeMuted() : false; +} + +void Application::setInternalLinkDomain(const QString &domain) const { + // This domain should start with 'http[s]://' and end with '/'. + // Like 'https://telegram.me/' or 'https://t.me/'. + auto validate = [](const auto &domain) { + const auto prefixes = { + qstr("https://"), + qstr("http://"), + }; + for (const auto &prefix : prefixes) { + if (domain.startsWith(prefix, Qt::CaseInsensitive)) { + return domain.endsWith('/'); + } + } + return false; + }; + if (validate(domain) && domain != Global::InternalLinksDomain()) { + Global::SetInternalLinksDomain(domain); + } +} + +QString Application::createInternalLink(const QString &query) const { + auto result = createInternalLinkFull(query); + auto prefixes = { + qstr("https://"), + qstr("http://"), + }; + for (auto &prefix : prefixes) { + if (result.startsWith(prefix, Qt::CaseInsensitive)) { + return result.mid(prefix.size()); + } + } + LOG(("Warning: bad internal url '%1'").arg(result)); + return result; +} + +QString Application::createInternalLinkFull(const QString &query) const { + return Global::InternalLinksDomain() + query; +} + +void Application::checkStartUrl() { + if (!cStartUrl().isEmpty() && !locked()) { + auto url = cStartUrl(); + cSetStartUrl(QString()); + if (!openLocalUrl(url, {})) { + cSetStartUrl(url); + } + } +} + +bool Application::openLocalUrl(const QString &url, QVariant context) { + auto urlTrimmed = url.trimmed(); + if (urlTrimmed.size() > 8192) urlTrimmed = urlTrimmed.mid(0, 8192); + + const auto protocol = qstr("tg://"); + if (!urlTrimmed.startsWith(protocol, Qt::CaseInsensitive) || locked()) { + return false; + } + auto command = urlTrimmed.midRef(protocol.size()); + + using namespace qthelp; + const auto options = RegExOption::CaseInsensitive; + for (const auto &[expression, handler] : LocalUrlHandlers()) { + const auto match = regex_match(expression, command, options); + if (match) { + return handler(match, context); + } + } + return false; +} + +void Application::lockByPasscode() { + _passcodeLock = true; + _window->setupPasscodeLock(); +} + +void Application::unlockPasscode() { + clearPasscodeLock(); + _window->clearPasscodeLock(); +} + +void Application::clearPasscodeLock() { + cSetPasscodeBadTries(0); + _passcodeLock = false; +} + +bool Application::passcodeLocked() const { + return _passcodeLock.current(); +} + +rpl::producer Application::passcodeLockChanges() const { + return _passcodeLock.changes(); +} + +rpl::producer Application::passcodeLockValue() const { + return _passcodeLock.value(); +} + +void Application::lockByTerms(const Window::TermsLock &data) { + if (!_termsLock || *_termsLock != data) { + _termsLock = std::make_unique(data); + _termsLockChanges.fire(true); + } +} + +void Application::unlockTerms() { + if (_termsLock) { + _termsLock = nullptr; + _termsLockChanges.fire(false); + } +} + +std::optional Application::termsLocked() const { + return _termsLock ? base::make_optional(*_termsLock) : std::nullopt; +} + +rpl::producer Application::termsLockChanges() const { + return _termsLockChanges.events(); +} + +rpl::producer Application::termsLockValue() const { + return rpl::single( + _termsLock != nullptr + ) | rpl::then(termsLockChanges()); +} + +void Application::termsDeleteNow() { + MTP::send(MTPaccount_DeleteAccount(MTP_string("Decline ToS update"))); +} + +bool Application::locked() const { + return passcodeLocked() || termsLocked(); +} + +rpl::producer Application::lockChanges() const { + return lockValue() | rpl::skip(1); +} + +rpl::producer Application::lockValue() const { + using namespace rpl::mappers; + return rpl::combine( + passcodeLockValue(), + termsLockValue(), + _1 || _2); +} + +MainWindow *Application::getActiveWindow() const { + return _window.get(); +} + +bool Application::closeActiveWindow() { + if (hideMediaView()) { + return true; + } + if (auto activeWindow = getActiveWindow()) { + if (!activeWindow->hideNoQuit()) { + activeWindow->close(); + } + return true; + } + return false; +} + +bool Application::minimizeActiveWindow() { + hideMediaView(); + if (auto activeWindow = getActiveWindow()) { + if (Global::WorkMode().value() == dbiwmTrayOnly) { + activeWindow->minimizeToTray(); + } else { + activeWindow->setWindowState(Qt::WindowMinimized); + } + return true; + } + return false; +} + +QWidget *Application::getFileDialogParent() { + return (_mediaView && _mediaView->isVisible()) ? (QWidget*)_mediaView.get() : (QWidget*)getActiveWindow(); +} + +void Application::checkMediaViewActivation() { + if (_mediaView && !_mediaView->isHidden()) { + _mediaView->activateWindow(); + QApplication::setActiveWindow(_mediaView.get()); + _mediaView->setFocus(); + } +} + +void Application::logOut() { + if (_mtproto) { + _mtproto->logout(::rpcDone([=] { + loggedOut(); + }), ::rpcFail([=] { + loggedOut(); + return true; + })); + } else { + // We log out because we've forgotten passcode. + // So we just start mtproto from scratch. + startMtp(); + loggedOut(); + } +} + +void Application::loggedOut() { + if (Global::LocalPasscode()) { + Global::SetLocalPasscode(false); + Global::RefLocalPasscodeChanged().notify(); + } + clearPasscodeLock(); + Media::Player::mixer()->stopAndClear(); + Global::SetVoiceMsgPlaybackDoubled(false); + Media::Player::mixer()->setVoicePlaybackDoubled(false); + if (const auto window = getActiveWindow()) { + window->tempDirDelete(Local::ClearManagerAll); + window->setupIntro(); + } + if (const auto session = authSession()) { + session->data().clearLocalStorage(); + authSessionDestroy(); + } + if (_mediaView) { + hideMediaView(); + _mediaView->clearData(); + } + Local::reset(); + + cSetOtherOnline(0); + Images::ClearRemote(); +} + +QPoint Application::getPointForCallPanelCenter() const { + if (auto activeWindow = getActiveWindow()) { + Assert(activeWindow->windowHandle() != nullptr); + if (activeWindow->isActive()) { + return activeWindow->geometry().center(); + } + return activeWindow->windowHandle()->screen()->geometry().center(); + } + return QApplication::desktop()->screenGeometry().center(); +} + +// macOS Qt bug workaround, sometimes no leaveEvent() gets to the nested widgets. +void Application::registerLeaveSubscription(QWidget *widget) { +#ifdef Q_OS_MAC + if (auto topLevel = widget->window()) { + if (topLevel == _window.get()) { + auto weak = make_weak(widget); + auto subscription = _window->leaveEvents( + ) | rpl::start_with_next([weak] { + if (const auto window = weak.data()) { + QEvent ev(QEvent::Leave); + QGuiApplication::sendEvent(window, &ev); + } + }); + _leaveSubscriptions.emplace_back(weak, std::move(subscription)); + } + } +#endif // Q_OS_MAC +} + +void Application::unregisterLeaveSubscription(QWidget *widget) { +#ifdef Q_OS_MAC + _leaveSubscriptions = std::move( + _leaveSubscriptions + ) | ranges::action::remove_if([&](const LeaveSubscription &subscription) { + auto pointer = subscription.pointer.data(); + return !pointer || (pointer == widget); + }); +#endif // Q_OS_MAC +} + +void Application::postponeCall(FnMut &&callable) { + Sandbox::Instance().postponeCall(std::move(callable)); +} + +void Application::refreshGlobalProxy() { + Sandbox::Instance().refreshGlobalProxy(); +} + +void Application::activateWindowDelayed(not_null widget) { + Sandbox::Instance().activateWindowDelayed(widget); +} + +void Application::pauseDelayedWindowActivations() { + Sandbox::Instance().pauseDelayedWindowActivations(); +} + +void Application::resumeDelayedWindowActivations() { + Sandbox::Instance().resumeDelayedWindowActivations(); +} + +void Application::preventWindowActivation() { + pauseDelayedWindowActivations(); + postponeCall([=] { + resumeDelayedWindowActivations(); + }); +} + +void Application::QuitAttempt() { + auto prevents = false; + if (AuthSession::Exists() && !Sandbox::Instance().isSavingSession()) { + if (const auto mainwidget = App::main()) { + if (mainwidget->isQuitPrevent()) { + prevents = true; + } + } + if (Auth().api().isQuitPrevent()) { + prevents = true; + } + if (Auth().calls().isQuitPrevent()) { + prevents = true; + } + } + if (prevents) { + App().quitDelayed(); + } else { + QApplication::quit(); + } +} + +void Application::quitPreventFinished() { + if (App::quitting()) { + QuitAttempt(); + } +} + +void Application::quitDelayed() { + if (!_private->quitTimer.isActive()) { + _private->quitTimer.setCallback([] { QApplication::quit(); }); + _private->quitTimer.callOnce(kQuitPreventTimeoutMs); + } +} + +void Application::startShortcuts() { + Shortcuts::Start(); + + Shortcuts::Requests( + ) | rpl::start_with_next([=](not_null request) { + using Command = Shortcuts::Command; + request->check(Command::Quit) && request->handle([] { + App::quit(); + return true; + }); + request->check(Command::Lock) && request->handle([=] { + if (!passcodeLocked() && Global::LocalPasscode()) { + lockByPasscode(); + return true; + } + return false; + }); + request->check(Command::Minimize) && request->handle([=] { + return minimizeActiveWindow(); + }); + request->check(Command::Close) && request->handle([=] { + return closeActiveWindow(); + }); + }, _lifetime); +} + +Application::~Application() { + _window.reset(); + _mediaView.reset(); + + // Some MTP requests can be cancelled from data clearing. + authSessionDestroy(); + + // The langpack manager should be destroyed before MTProto instance, + // because it is MTP::Sender and it may have pending requests. + _langCloudManager.reset(); + + _mtproto.reset(); + _mtprotoForKeysDestroy.reset(); + + Shortcuts::Finish(); + + Ui::Emoji::Clear(); + + anim::stopManager(); + + stopWebLoadManager(); + App::deinitMedia(); + + Window::Theme::Unload(); + + Media::Player::finish(_audio.get()); + style::stopManager(); + + Local::finish(); + Global::finish(); + ThirdParty::finish(); +} + +Application &App() { + return Sandbox::Instance().application(); +} + +} // namespace Core diff -Nru telegram-desktop-1.5.8/Telegram/SourceFiles/core/application.h telegram-desktop-1.5.11/Telegram/SourceFiles/core/application.h --- telegram-desktop-1.5.8/Telegram/SourceFiles/core/application.h 1970-01-01 00:00:00.000000000 +0000 +++ telegram-desktop-1.5.11/Telegram/SourceFiles/core/application.h 2019-02-01 12:51:46.000000000 +0000 @@ -0,0 +1,287 @@ +/* +This file is part of Telegram Desktop, +the official desktop application for the Telegram messaging service. + +For license and copyright information please follow this link: +https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL +*/ +#pragma once + +#include "base/observer.h" +#include "mtproto/auth_key.h" +#include "base/timer.h" + +class AuthSession; +class AuthSessionSettings; +class MainWidget; +class FileUploader; +class Translator; +class MediaView; +class BoxContent; + +namespace Storage { +class Databases; +} // namespace Storage + +namespace Window { +struct TermsLock; +} // namespace Window + +namespace App { +void quit(); +} // namespace App + +namespace MTP { +class DcOptions; +class Instance; +class AuthKey; +using AuthKeyPtr = std::shared_ptr; +using AuthKeysList = std::vector; +} // namespace MTP + +namespace Media { +namespace Audio { +class Instance; +} // namespace Audio +} // namespace Media + +namespace Lang { +class Instance; +class Translator; +class CloudManager; +} // namespace Lang + +namespace Core { + +class Launcher; +struct LocalUrlHandler; + +class Application final + : public QObject + , public RPCSender + , private base::Subscriber { +public: + Application(not_null launcher); + + Application(const Application &other) = delete; + Application &operator=(const Application &other) = delete; + + not_null launcher() const { + return _launcher; + } + + void run(); + + // Windows interface. + MainWindow *getActiveWindow() const; + bool closeActiveWindow(); + bool minimizeActiveWindow(); + QWidget *getFileDialogParent(); + QWidget *getGlobalShortcutParent() { + return &_globalShortcutParent; + } + + // MediaView interface. + void checkMediaViewActivation(); + bool hideMediaView(); + void showPhoto(not_null link); + void showPhoto(not_null photo, HistoryItem *item); + void showPhoto(not_null photo, not_null item); + void showDocument(not_null document, HistoryItem *item); + PeerData *ui_getPeerForMouseAction(); + + QPoint getPointForCallPanelCenter() const; + QImage logo() const { + return _logo; + } + QImage logoNoMargin() const { + return _logoNoMargin; + } + + // MTProto components. + MTP::DcOptions *dcOptions() { + return _dcOptions.get(); + } + void setCurrentProxy( + const ProxyData &proxy, + ProxyData::Settings settings); + void badMtprotoConfigurationError(); + + // Set from legacy storage. + void setMtpMainDcId(MTP::DcId mainDcId); + void setMtpKey(MTP::DcId dcId, const MTP::AuthKey::Data &keyData); + void setAuthSessionUserId(UserId userId); + void setAuthSessionFromStorage( + std::unique_ptr data, + QByteArray &&selfSerialized, + int32 selfStreamVersion); + AuthSessionSettings *getAuthSessionSettings(); + + // Serialization. + QByteArray serializeMtpAuthorization() const; + void setMtpAuthorization(const QByteArray &serialized); + + void startMtp(); + MTP::Instance *mtp() { + return _mtproto.get(); + } + void suggestMainDcId(MTP::DcId mainDcId); + void destroyStaleAuthorizationKeys(); + + // Databases + Storage::Databases &databases() { + return *_databases; + } + + // AuthSession component. + AuthSession *authSession() { + return _authSession.get(); + } + Lang::Instance &langpack() { + return *_langpack; + } + Lang::CloudManager *langCloudManager() { + return _langCloudManager.get(); + } + void authSessionCreate(const MTPUser &user); + base::Observable &authSessionChanged() { + return _authSessionChanged; + } + int unreadBadge() const; + bool unreadBadgeMuted() const; + void logOut(); + + // Media component. + Media::Audio::Instance &audio() { + return *_audio; + } + + // Internal links. + void setInternalLinkDomain(const QString &domain) const; + QString createInternalLink(const QString &query) const; + QString createInternalLinkFull(const QString &query) const; + void checkStartUrl(); + bool openLocalUrl(const QString &url, QVariant context); + + void forceLogOut(const TextWithEntities &explanation); + void checkLocalTime(); + void lockByPasscode(); + void unlockPasscode(); + [[nodiscard]] bool passcodeLocked() const; + rpl::producer passcodeLockChanges() const; + rpl::producer passcodeLockValue() const; + + void lockByTerms(const Window::TermsLock &data); + void unlockTerms(); + [[nodiscard]] std::optional termsLocked() const; + rpl::producer termsLockChanges() const; + rpl::producer termsLockValue() const; + void termsDeleteNow(); + + [[nodiscard]] bool locked() const; + rpl::producer lockChanges() const; + rpl::producer lockValue() const; + + void registerLeaveSubscription(QWidget *widget); + void unregisterLeaveSubscription(QWidget *widget); + + // Sandbox interface. + void postponeCall(FnMut &&callable); + void refreshGlobalProxy(); + void activateWindowDelayed(not_null widget); + void pauseDelayedWindowActivations(); + void resumeDelayedWindowActivations(); + void preventWindowActivation(); + + void quitPreventFinished(); + + void handleAppActivated(); + void handleAppDeactivated(); + + void switchDebugMode(); + void switchWorkMode(); + void switchTestMode(); + void writeInstallBetaVersionsSetting(); + + void call_handleUnreadCounterUpdate(); + void call_handleDelayedPeerUpdates(); + void call_handleObservables(); + + void callDelayed(int duration, FnMut &&lambda) { + _callDelayedTimer.call(duration, std::move(lambda)); + } + + ~Application(); + +protected: + bool eventFilter(QObject *object, QEvent *event) override; + +private: + void destroyMtpKeys(MTP::AuthKeysList &&keys); + void allKeysDestroyed(); + + void startLocalStorage(); + void startShortcuts(); + + void stateChanged(Qt::ApplicationState state); + + friend void App::quit(); + static void QuitAttempt(); + void quitDelayed(); + + void resetAuthorizationKeys(); + void authSessionDestroy(); + void clearPasscodeLock(); + void loggedOut(); + + not_null _launcher; + + // Some fields are just moved from the declaration. + struct Private; + const std::unique_ptr _private; + + QWidget _globalShortcutParent; + + std::unique_ptr _databases; + std::unique_ptr _window; + std::unique_ptr _mediaView; + std::unique_ptr _langpack; + std::unique_ptr _langCloudManager; + std::unique_ptr _translator; + std::unique_ptr _dcOptions; + std::unique_ptr _mtproto; + std::unique_ptr _mtprotoForKeysDestroy; + std::unique_ptr _authSession; + base::Observable _authSessionChanged; + base::Observable _passcodedChanged; + QPointer _badProxyDisableBox; + + std::unique_ptr _audio; + QImage _logo; + QImage _logoNoMargin; + + rpl::variable _passcodeLock; + rpl::event_stream _termsLockChanges; + std::unique_ptr _termsLock; + + base::DelayedCallTimer _callDelayedTimer; + + struct LeaveSubscription { + LeaveSubscription( + QPointer pointer, + rpl::lifetime &&subscription) + : pointer(pointer), subscription(std::move(subscription)) { + } + + QPointer pointer; + rpl::lifetime subscription; + }; + std::vector _leaveSubscriptions; + + rpl::lifetime _lifetime; + +}; + +Application &App(); + +} // namespace Core diff -Nru telegram-desktop-1.5.8/Telegram/SourceFiles/core/click_handler_types.cpp telegram-desktop-1.5.11/Telegram/SourceFiles/core/click_handler_types.cpp --- telegram-desktop-1.5.8/Telegram/SourceFiles/core/click_handler_types.cpp 2019-01-21 17:28:45.000000000 +0000 +++ telegram-desktop-1.5.11/Telegram/SourceFiles/core/click_handler_types.cpp 2019-02-01 12:51:46.000000000 +0000 @@ -8,9 +8,11 @@ #include "core/click_handler_types.h" #include "lang/lang_keys.h" -#include "messenger.h" +#include "core/application.h" +#include "core/local_url_handlers.h" +#include "core/file_utilities.h" #include "mainwidget.h" -#include "application.h" +#include "auth_session.h" #include "platform/platform_specific.h" #include "history/view/history_view_element.h" #include "history/history_item.h" @@ -19,8 +21,8 @@ #include "base/qthelp_url.h" #include "storage/localstorage.h" #include "ui/widgets/tooltip.h" -#include "core/file_utilities.h" #include "data/data_user.h" +#include "data/data_session.h" namespace { @@ -115,7 +117,7 @@ void UrlClickHandler::Open(QString url, QVariant context) { url = tryConvertUrlToLocal(url); - if (InternalPassportLink(url)) { + if (Core::InternalPassportLink(url)) { return; } @@ -123,7 +125,7 @@ if (isEmail(url)) { File::OpenEmailLink(url); } else if (url.startsWith(qstr("tg://"), Qt::CaseInsensitive)) { - Messenger::Instance().openLocalUrl(url, context); + Core::App().openLocalUrl(url, context); } else if (!url.isEmpty()) { QDesktopServices::openUrl(url); } @@ -151,7 +153,7 @@ void HiddenUrlClickHandler::Open(QString url, QVariant context) { url = tryConvertUrlToLocal(url); - if (InternalPassportLink(url)) { + if (Core::InternalPassportLink(url)) { return; } @@ -163,7 +165,7 @@ } else { const auto parsedUrl = QUrl::fromUserInput(url); if (UrlRequiresConfirmation(url)) { - Messenger::Instance().hideMediaView(); + Core::App().hideMediaView(); const auto displayUrl = parsedUrl.isValid() ? parsedUrl.toDisplayString() : url; @@ -181,7 +183,7 @@ void BotGameUrlClickHandler::onClick(ClickContext context) const { const auto url = tryConvertUrlToLocal(this->url()); - if (InternalPassportLink(url)) { + if (Core::InternalPassportLink(url)) { return; } @@ -247,7 +249,7 @@ void MentionNameClickHandler::onClick(ClickContext context) const { const auto button = context.button; if (button == Qt::LeftButton || button == Qt::MiddleButton) { - if (auto user = App::userLoaded(_userId)) { + if (auto user = Auth().data().userLoaded(_userId)) { Ui::showPeerProfile(user); } } @@ -259,7 +261,7 @@ } QString MentionNameClickHandler::tooltip() const { - if (auto user = App::userLoaded(_userId)) { + if (auto user = Auth().data().userLoaded(_userId)) { auto name = App::peerName(user); if (name != _text) { return name; diff -Nru telegram-desktop-1.5.8/Telegram/SourceFiles/core/crash_reports.cpp telegram-desktop-1.5.11/Telegram/SourceFiles/core/crash_reports.cpp --- telegram-desktop-1.5.8/Telegram/SourceFiles/core/crash_reports.cpp 2019-01-21 17:28:45.000000000 +0000 +++ telegram-desktop-1.5.11/Telegram/SourceFiles/core/crash_reports.cpp 2019-02-01 12:51:46.000000000 +0000 @@ -8,6 +8,7 @@ #include "core/crash_reports.h" #include "platform/platform_specific.h" +#include "core/launcher.h" #include #include @@ -319,14 +320,14 @@ } // namespace -void StartCatching() { +void StartCatching(not_null launcher) { #ifndef TDESKTOP_DISABLE_CRASH_REPORTS ProcessAnnotations["Binary"] = cExeName().toUtf8().constData(); ProcessAnnotations["ApiId"] = QString::number(ApiId).toUtf8().constData(); ProcessAnnotations["Version"] = (cAlphaVersion() ? qsl("%1 alpha").arg(cAlphaVersion()) : (AppBetaVersion ? qsl("%1 beta") : qsl("%1")).arg(AppVersion)).toUtf8().constData(); ProcessAnnotations["Launched"] = QDateTime::currentDateTime().toString("dd.MM.yyyy hh:mm:ss").toUtf8().constData(); ProcessAnnotations["Platform"] = cPlatformString().toUtf8().constData(); - ProcessAnnotations["UserTag"] = QString::number(Sandbox::UserTag(), 16).toUtf8().constData(); + ProcessAnnotations["UserTag"] = QString::number(launcher->installationTag(), 16).toUtf8().constData(); QString dumpspath = cWorkingDir() + qsl("tdata/dumps"); QDir().mkpath(dumpspath); @@ -393,7 +394,7 @@ #endif // !TDESKTOP_DISABLE_CRASH_REPORTS } -Status Start() { +StartResult Start() { #ifndef TDESKTOP_DISABLE_CRASH_REPORTS ReportPath = cWorkingDir() + qsl("tdata/working"); @@ -413,11 +414,11 @@ } fclose(f); - Sandbox::SetLastCrashDump(lastdump); + LOG(("Opened '%1' for reading, the previous " + "Telegram Desktop launch was not finished properly :( " + "Crash log size: %2").arg(ReportPath).arg(lastdump.size())); - LOG(("Opened '%1' for reading, the previous Telegram Desktop launch was not finished properly :( Crash log size: %2").arg(ReportPath).arg(lastdump.size())); - - return LastCrashed; + return lastdump; } #endif // !TDESKTOP_DISABLE_CRASH_REPORTS diff -Nru telegram-desktop-1.5.8/Telegram/SourceFiles/core/crash_reports.h telegram-desktop-1.5.11/Telegram/SourceFiles/core/crash_reports.h --- telegram-desktop-1.5.8/Telegram/SourceFiles/core/crash_reports.h 2019-01-21 17:28:45.000000000 +0000 +++ telegram-desktop-1.5.11/Telegram/SourceFiles/core/crash_reports.h 2019-02-01 12:51:46.000000000 +0000 @@ -7,6 +7,10 @@ */ #pragma once +namespace Core { +class Launcher; +} // namespace Core + namespace CrashReports { #ifndef TDESKTOP_DISABLE_CRASH_REPORTS @@ -26,10 +30,11 @@ enum Status { CantOpen, - LastCrashed, Started }; -Status Start(); +// Open status or crash report dump. +using StartResult = base::variant; +StartResult Start(); Status Restart(); // can be only CantOpen or Started void Finish(); @@ -46,7 +51,7 @@ SetAnnotationRef(key, nullptr); } -void StartCatching(); +void StartCatching(not_null launcher); void FinishCatching(); } // namespace CrashReports diff -Nru telegram-desktop-1.5.8/Telegram/SourceFiles/core/crash_report_window.cpp telegram-desktop-1.5.11/Telegram/SourceFiles/core/crash_report_window.cpp --- telegram-desktop-1.5.8/Telegram/SourceFiles/core/crash_report_window.cpp 2019-01-21 17:28:45.000000000 +0000 +++ telegram-desktop-1.5.11/Telegram/SourceFiles/core/crash_report_window.cpp 2019-02-01 12:51:46.000000000 +0000 @@ -8,11 +8,18 @@ #include "core/crash_report_window.h" #include "core/crash_reports.h" +#include "core/launcher.h" +#include "core/sandbox.h" +#include "core/update_checker.h" #include "window/main_window.h" #include "platform/platform_specific.h" -#include "application.h" #include "base/zlib_help.h" -#include "core/update_checker.h" + +namespace { + +constexpr auto kDefaultProxyPort = 80; + +} // namespace PreLaunchWindow *PreLaunchWindowInstance = nullptr; @@ -198,8 +205,12 @@ , skip(buttonParent, false) { } -LastCrashedWindow::LastCrashedWindow() -: _port(80) +LastCrashedWindow::LastCrashedWindow( + not_null launcher, + const QByteArray &crashdump, + Fn launch) +: _dumpraw(crashdump) +, _port(kDefaultProxyPort) , _label(this) , _pleaseSendReport(this) , _yourReportName(this) @@ -213,18 +224,15 @@ , _saveReport(this) , _getApp(this) , _includeUsername(this) -, _reportText(QString::fromUtf8(Sandbox::LastCrashDump())) +, _reportText(QString::fromUtf8(crashdump)) , _reportShown(false) , _reportSaved(false) -, _sendingState(Sandbox::LastCrashDump().isEmpty() ? SendingNoReport : SendingUpdateCheck) +, _sendingState(crashdump.isEmpty() ? SendingNoReport : SendingUpdateCheck) , _updating(this) -, _sendingProgress(0) -, _sendingTotal(0) -, _checkReply(0) -, _sendReply(0) , _updaterData(Core::UpdaterDisabled() ? nullptr - : std::make_unique(this)) { + : std::make_unique(this)) +, _launch(std::move(launch)) { excludeReportUsername(); if (!cInstallBetaVersion() && !cAlphaVersion()) { // currently accept crash reports only from testers @@ -339,7 +347,7 @@ } _pleaseSendReport.setText(qsl("Please send us a crash report.")); - _yourReportName.setText(qsl("Your Report Tag: %1\nYour User Tag: %2").arg(QString(_minidumpName).replace(".dmp", "")).arg(Sandbox::UserTag(), 0, 16)); + _yourReportName.setText(qsl("Your Report Tag: %1\nYour User Tag: %2").arg(QString(_minidumpName).replace(".dmp", "")).arg(launcher->installationTag(), 0, 16)); _yourReportName.setCursor(style::cur_text); _yourReportName.setTextInteractionFlags(Qt::TextSelectableByMouse); @@ -386,9 +394,11 @@ } QByteArray LastCrashedWindow::getCrashReportRaw() const { - QByteArray result(Sandbox::LastCrashDump()); + auto result = _dumpraw; if (!_reportUsername.isEmpty() && _includeUsername.checkState() != Qt::Checked) { - result.replace((qsl("Username: ") + _reportUsername).toUtf8(), "Username: _not_included_"); + result.replace( + (qsl("Username: ") + _reportUsername).toUtf8(), + "Username: _not_included_"); } return result; } @@ -775,7 +785,7 @@ } void LastCrashedWindow::onNetworkSettings() { - const auto &proxy = Sandbox::PreLaunchProxy(); + const auto &proxy = Core::Sandbox::Instance().sandboxProxy(); const auto box = new NetworkSettingsWindow( this, proxy.host, @@ -797,7 +807,7 @@ QString password) { Expects(host.isEmpty() || port != 0); - auto &proxy = Sandbox::RefPreLaunchProxy(); + auto proxy = ProxyData(); proxy.type = host.isEmpty() ? ProxyData::Type::None : ProxyData::Type::Http; @@ -805,9 +815,11 @@ proxy.port = port; proxy.user = username; proxy.password = password; + _proxyChanges.fire(std::move(proxy)); + proxyUpdated(); +} - Core::App().refreshGlobalProxy(); - +void LastCrashedWindow::proxyUpdated() { if (_updaterData && ((_updaterData->state == UpdatingCheck) || (_updaterData->state == UpdatingFail @@ -824,6 +836,10 @@ activate(); } +rpl::producer LastCrashedWindow::proxyChanges() const { + return _proxyChanges.events(); +} + void LastCrashedWindow::setUpdatingState(UpdatingState state, bool force) { Expects(_updaterData != nullptr); @@ -932,8 +948,8 @@ void LastCrashedWindow::onContinue() { if (CrashReports::Restart() == CrashReports::CantOpen) { new NotStartedWindow(); - } else if (!Global::started()) { - Sandbox::launch(); + } else { + _launch(); } close(); } diff -Nru telegram-desktop-1.5.8/Telegram/SourceFiles/core/crash_report_window.h telegram-desktop-1.5.11/Telegram/SourceFiles/core/crash_report_window.h --- telegram-desktop-1.5.8/Telegram/SourceFiles/core/crash_report_window.h 2019-01-21 17:28:45.000000000 +0000 +++ telegram-desktop-1.5.11/Telegram/SourceFiles/core/crash_report_window.h 2019-02-01 12:51:46.000000000 +0000 @@ -7,6 +7,10 @@ */ #pragma once +namespace Core { +class Launcher; +} // namespace Core + class PreLaunchWindow : public QWidget { public: PreLaunchWindow(QString title = QString()); @@ -62,8 +66,8 @@ NotStartedWindow(); protected: - void closeEvent(QCloseEvent *e); - void resizeEvent(QResizeEvent *e); + void closeEvent(QCloseEvent *e) override; + void resizeEvent(QResizeEvent *e) override; private: void updateControls(); @@ -78,7 +82,16 @@ Q_OBJECT public: - LastCrashedWindow(); + LastCrashedWindow( + not_null launcher, + const QByteArray &crashdump, + Fn launch); + + rpl::producer proxyChanges() const; + + rpl::lifetime &lifetime() { + return _lifetime; + } public slots: void onViewReport(); @@ -105,10 +118,11 @@ void onUpdateFailed(); protected: - void closeEvent(QCloseEvent *e); - void resizeEvent(QResizeEvent *e); + void closeEvent(QCloseEvent *e) override; + void resizeEvent(QResizeEvent *e) override; private: + void proxyUpdated(); QString minidumpFileName(); void updateControls(); @@ -117,6 +131,8 @@ QString getReportField(const QLatin1String &name, const QLatin1String &prefix); void addReportFieldPart(const QLatin1String &name, const QLatin1String &prefix, QHttpMultiPart *multipart); + QByteArray _dumpraw; + QString _host, _username, _password; quint32 _port; @@ -146,10 +162,12 @@ SendingState _sendingState; PreLaunchLabel _updating; - qint64 _sendingProgress, _sendingTotal; + qint64 _sendingProgress = 0; + qint64 _sendingTotal = 0; QNetworkAccessManager _sendManager; - QNetworkReply *_checkReply, *_sendReply; + QNetworkReply *_checkReply = nullptr; + QNetworkReply *_sendReply = nullptr; enum UpdatingState { UpdatingNone, @@ -171,6 +189,8 @@ void setUpdatingState(UpdatingState state, bool force = false); void setDownloadProgress(qint64 ready, qint64 total); + Fn _launch; + rpl::event_stream _proxyChanges; rpl::lifetime _lifetime; }; diff -Nru telegram-desktop-1.5.8/Telegram/SourceFiles/core/file_utilities.cpp telegram-desktop-1.5.11/Telegram/SourceFiles/core/file_utilities.cpp --- telegram-desktop-1.5.8/Telegram/SourceFiles/core/file_utilities.cpp 2019-01-21 17:28:45.000000000 +0000 +++ telegram-desktop-1.5.11/Telegram/SourceFiles/core/file_utilities.cpp 2019-02-01 12:51:46.000000000 +0000 @@ -9,17 +9,9 @@ #include "storage/localstorage.h" #include "platform/platform_file_utilities.h" -#include "messenger.h" -#include "application.h" +#include "core/application.h" #include "mainwindow.h" -void PreventWindowActivation() { - Core::App().pauseDelayedWindowActivations(); - Core::App().postponeCall([] { - Core::App().resumeDelayedWindowActivations(); - }); -} - bool filedialogGetSaveFile( QPointer parent, QString &file, @@ -28,7 +20,7 @@ const QString &initialPath) { QStringList files; QByteArray remoteContent; - PreventWindowActivation(); + Core::App().preventWindowActivation(); bool result = Platform::FileDialog::Get( parent, files, @@ -47,7 +39,7 @@ const QString &filter, const QString &initialPath) { return filedialogGetSaveFile( - Messenger::Instance().getFileDialogParent(), + Core::App().getFileDialogParent(), file, caption, filter, @@ -121,7 +113,7 @@ void OpenEmailLink(const QString &email) { crl::on_main([=] { - PreventWindowActivation(); + Core::App().preventWindowActivation(); Platform::File::UnsafeOpenEmailLink(email); }); } @@ -129,7 +121,7 @@ void OpenWith(const QString &filepath, QPoint menuPosition) { InvokeQueued(QApplication::instance(), [=] { if (!Platform::File::UnsafeShowOpenWithDropdown(filepath, menuPosition)) { - PreventWindowActivation(); + Core::App().preventWindowActivation(); if (!Platform::File::UnsafeShowOpenWith(filepath)) { Platform::File::UnsafeLaunch(filepath); } @@ -139,14 +131,14 @@ void Launch(const QString &filepath) { crl::on_main([=] { - PreventWindowActivation(); + Core::App().preventWindowActivation(); Platform::File::UnsafeLaunch(filepath); }); } void ShowInFolder(const QString &filepath) { crl::on_main([=] { - PreventWindowActivation(); + Core::App().preventWindowActivation(); Platform::File::UnsafeShowInFolder(filepath); }); } @@ -186,7 +178,7 @@ InvokeQueued(QApplication::instance(), [=] { auto files = QStringList(); auto remoteContent = QByteArray(); - PreventWindowActivation(); + Core::App().preventWindowActivation(); const auto success = Platform::FileDialog::Get( parent, files, @@ -220,7 +212,7 @@ InvokeQueued(QApplication::instance(), [=] { auto files = QStringList(); auto remoteContent = QByteArray(); - PreventWindowActivation(); + Core::App().preventWindowActivation(); const auto success = Platform::FileDialog::Get( parent, files, @@ -269,7 +261,7 @@ InvokeQueued(QApplication::instance(), [=] { auto files = QStringList(); auto remoteContent = QByteArray(); - PreventWindowActivation(); + Core::App().preventWindowActivation(); const auto success = Platform::FileDialog::Get( parent, files, @@ -320,7 +312,7 @@ } QString file; if (type == Type::ReadFiles) { - files = QFileDialog::getOpenFileNames(Messenger::Instance().getFileDialogParent(), caption, startFile, filter); + files = QFileDialog::getOpenFileNames(Core::App().getFileDialogParent(), caption, startFile, filter); QString path = files.isEmpty() ? QString() : QFileInfo(files.back()).absoluteDir().absolutePath(); if (!path.isEmpty() && path != cDialogLastPath()) { cSetDialogLastPath(path); @@ -328,11 +320,11 @@ } return !files.isEmpty(); } else if (type == Type::ReadFolder) { - file = QFileDialog::getExistingDirectory(Messenger::Instance().getFileDialogParent(), caption, startFile); + file = QFileDialog::getExistingDirectory(Core::App().getFileDialogParent(), caption, startFile); } else if (type == Type::WriteFile) { - file = QFileDialog::getSaveFileName(Messenger::Instance().getFileDialogParent(), caption, startFile, filter); + file = QFileDialog::getSaveFileName(Core::App().getFileDialogParent(), caption, startFile, filter); } else { - file = QFileDialog::getOpenFileName(Messenger::Instance().getFileDialogParent(), caption, startFile, filter); + file = QFileDialog::getOpenFileName(Core::App().getFileDialogParent(), caption, startFile, filter); } if (file.isEmpty()) { files = QStringList(); diff -Nru telegram-desktop-1.5.8/Telegram/SourceFiles/core/launcher.cpp telegram-desktop-1.5.11/Telegram/SourceFiles/core/launcher.cpp --- telegram-desktop-1.5.8/Telegram/SourceFiles/core/launcher.cpp 2019-01-21 17:28:45.000000000 +0000 +++ telegram-desktop-1.5.11/Telegram/SourceFiles/core/launcher.cpp 2019-02-01 12:51:46.000000000 +0000 @@ -12,10 +12,179 @@ #include "core/crash_reports.h" #include "core/main_queue_processor.h" #include "core/update_checker.h" +#include "core/sandbox.h" #include "base/concurrent_timer.h" -#include "application.h" namespace Core { +namespace { + +uint64 InstallationTag = 0; + +QString DebugModeSettingPath() { + return cWorkingDir() + qsl("tdata/withdebug"); +} + +void WriteDebugModeSetting() { + auto file = QFile(DebugModeSettingPath()); + if (file.open(QIODevice::WriteOnly)) { + file.write(Logs::DebugEnabled() ? "1" : "0"); + } +} + +void ComputeDebugMode() { + Logs::SetDebugEnabled(cAlphaVersion() != 0); + const auto debugModeSettingPath = DebugModeSettingPath(); + auto file = QFile(debugModeSettingPath); + if (file.exists() && file.open(QIODevice::ReadOnly)) { + Logs::SetDebugEnabled(file.read(1) != "0"); + } +} + +void ComputeTestMode() { + if (QFile(cWorkingDir() + qsl("tdata/withtestmode")).exists()) { + cSetTestMode(true); + } +} + +QString InstallBetaVersionsSettingPath() { + return cWorkingDir() + qsl("tdata/devversion"); +} + +void WriteInstallBetaVersionsSetting() { + QFile f(InstallBetaVersionsSettingPath()); + if (f.open(QIODevice::WriteOnly)) { + f.write(cInstallBetaVersion() ? "1" : "0"); + } +} + +void ComputeInstallBetaVersions() { + const auto installBetaSettingPath = InstallBetaVersionsSettingPath(); + if (cAlphaVersion()) { + cSetInstallBetaVersion(false); + } else if (QFile(installBetaSettingPath).exists()) { + QFile f(installBetaSettingPath); + if (f.open(QIODevice::ReadOnly)) { + cSetInstallBetaVersion(f.read(1) != "0"); + } + } else if (AppBetaVersion) { + WriteInstallBetaVersionsSetting(); + } +} + +void ComputeInstallationTag() { + InstallationTag = 0; + auto file = QFile(cWorkingDir() + qsl("tdata/usertag")); + if (file.open(QIODevice::ReadOnly)) { + const auto result = file.read( + reinterpret_cast(&InstallationTag), + sizeof(uint64)); + if (result != sizeof(uint64)) { + InstallationTag = 0; + } + file.close(); + } + if (!InstallationTag) { + do { + memsetrnd_bad(InstallationTag); + } while (!InstallationTag); + + if (file.open(QIODevice::WriteOnly)) { + file.write( + reinterpret_cast(&InstallationTag), + sizeof(uint64)); + file.close(); + } + } +} + +bool MoveLegacyAlphaFolder(const QString &folder, const QString &file) { + const auto was = cExeDir() + folder; + const auto now = cExeDir() + qsl("TelegramForcePortable"); + if (QDir(was).exists() && !QDir(now).exists()) { + const auto oldFile = was + "/tdata/" + file; + const auto newFile = was + "/tdata/alpha"; + if (QFile(oldFile).exists() && !QFile(newFile).exists()) { + if (!QFile(oldFile).copy(newFile)) { + LOG(("FATAL: Could not copy '%1' to '%2'" + ).arg(oldFile + ).arg(newFile)); + return false; + } + } + if (!QDir().rename(was, now)) { + LOG(("FATAL: Could not rename '%1' to '%2'" + ).arg(was + ).arg(now)); + return false; + } + } + return true; +} + +bool MoveLegacyAlphaFolder() { + if (!MoveLegacyAlphaFolder(qsl("TelegramAlpha_data"), qsl("alpha")) + || !MoveLegacyAlphaFolder(qsl("TelegramBeta_data"), qsl("beta"))) { + return false; + } + return true; +} + +bool CheckPortableVersionFolder() { + if (!MoveLegacyAlphaFolder()) { + return false; + } + + const auto portable = cExeDir() + qsl("TelegramForcePortable"); + QFile key(portable + qsl("/tdata/alpha")); + if (cAlphaVersion()) { + Assert(*AlphaPrivateKey != 0); + + cForceWorkingDir(portable + '/'); + QDir().mkpath(cWorkingDir() + qstr("tdata")); + cSetAlphaPrivateKey(QByteArray(AlphaPrivateKey)); + if (!key.open(QIODevice::WriteOnly)) { + LOG(("FATAL: Could not open '%1' for writing private key!" + ).arg(key.fileName())); + return false; + } + QDataStream dataStream(&key); + dataStream.setVersion(QDataStream::Qt_5_3); + dataStream << quint64(cRealAlphaVersion()) << cAlphaPrivateKey(); + return true; + } + if (!QDir(portable).exists()) { + return true; + } + cForceWorkingDir(portable + '/'); + if (!key.exists()) { + return true; + } + + if (!key.open(QIODevice::ReadOnly)) { + LOG(("FATAL: could not open '%1' for reading private key. " + "Delete it or reinstall private alpha version." + ).arg(key.fileName())); + return false; + } + QDataStream dataStream(&key); + dataStream.setVersion(QDataStream::Qt_5_3); + + quint64 v; + QByteArray k; + dataStream >> v >> k; + if (dataStream.status() != QDataStream::Ok || k.isEmpty()) { + LOG(("FATAL: '%1' is corrupted. " + "Delete it or reinstall private alpha version." + ).arg(key.fileName())); + return false; + } + cSetAlphaVersion(AppVersion * 1000ULL); + cSetAlphaPrivateKey(k); + cSetRealAlphaVersion(v); + return true; +} + +} // namespace std::unique_ptr Launcher::Create(int argc, char *argv[]) { return std::make_unique(argc, argv); @@ -37,10 +206,10 @@ prepareSettings(); - QCoreApplication::setApplicationName(qsl("TelegramDesktop")); + QApplication::setApplicationName(qsl("TelegramDesktop")); #ifndef OS_MAC_OLD - QCoreApplication::setAttribute(Qt::AA_DisableHighDpiScaling, true); + QApplication::setAttribute(Qt::AA_DisableHighDpiScaling, true); #endif // OS_MAC_OLD initHook(); @@ -55,21 +224,21 @@ return psCleanup(); } - // both are finished in Application::closeApplication + // both are finished in Sandbox::closeApplication Logs::start(this); // must be started before Platform is started - Platform::start(); // must be started before QApplication is created + Platform::start(); // must be started before Sandbox is created auto result = executeApplication(); DEBUG_LOG(("Telegram finished, result: %1").arg(result)); if (!UpdaterDisabled() && cRestartingUpdate()) { - DEBUG_LOG(("Application Info: executing updater to install update...")); + DEBUG_LOG(("Sandbox Info: executing updater to install update.")); if (!launchUpdater(UpdaterLaunch::PerformUpdate)) { psDeleteDir(cWorkingDir() + qsl("tupdates/temp")); } } else if (cRestarting()) { - DEBUG_LOG(("Application Info: executing Telegram, because of restart...")); + DEBUG_LOG(("Sandbox Info: executing Telegram because of restart.")); launchUpdater(UpdaterLaunch::JustRelaunch); } @@ -80,6 +249,27 @@ return result; } +void Launcher::workingFolderReady() { + srand((unsigned int)time(nullptr)); + + ComputeTestMode(); + ComputeDebugMode(); + ComputeInstallBetaVersions(); + ComputeInstallationTag(); +} + +void Launcher::writeDebugModeSetting() { + WriteDebugModeSetting(); +} + +void Launcher::writeInstallBetaVersionsSetting() { + WriteInstallBetaVersionsSetting(); +} + +bool Launcher::checkPortableVersionFolder() { + return CheckPortableVersionFolder(); +} + QStringList Launcher::readArguments(int argc, char *argv[]) const { Expects(argc >= 0); @@ -170,6 +360,10 @@ return _systemVersion; } +uint64 Launcher::installationTag() const { + return InstallationTag; +} + void Launcher::processArguments() { enum class KeyFormat { NoValues, @@ -243,10 +437,10 @@ } int Launcher::executeApplication() { - Application application(this, _argc, _argv); + Sandbox sandbox(this, _argc, _argv); MainQueueProcessor processor; base::ConcurrentTimerEnvironment environment; - return application.execute(); + return sandbox.start(); } } // namespace Core diff -Nru telegram-desktop-1.5.8/Telegram/SourceFiles/core/launcher.h telegram-desktop-1.5.11/Telegram/SourceFiles/core/launcher.h --- telegram-desktop-1.5.8/Telegram/SourceFiles/core/launcher.h 2019-01-21 17:28:45.000000000 +0000 +++ telegram-desktop-1.5.11/Telegram/SourceFiles/core/launcher.h 2019-02-01 12:51:46.000000000 +0000 @@ -24,9 +24,14 @@ QString argumentsString() const; bool customWorkingDir() const; - // Thread safe. QString deviceModel() const; QString systemVersion() const; + uint64 installationTag() const; + + bool checkPortableVersionFolder(); + void workingFolderReady(); + void writeDebugModeSetting(); + void writeInstallBetaVersionsSetting(); virtual ~Launcher() = default; diff -Nru telegram-desktop-1.5.8/Telegram/SourceFiles/core/local_url_handlers.cpp telegram-desktop-1.5.11/Telegram/SourceFiles/core/local_url_handlers.cpp --- telegram-desktop-1.5.8/Telegram/SourceFiles/core/local_url_handlers.cpp 2019-01-21 17:28:45.000000000 +0000 +++ telegram-desktop-1.5.11/Telegram/SourceFiles/core/local_url_handlers.cpp 2019-02-01 12:51:46.000000000 +0000 @@ -20,9 +20,10 @@ #include "boxes/sticker_set_box.h" #include "passport/passport_form_controller.h" #include "window/window_controller.h" +#include "data/data_session.h" #include "mainwindow.h" #include "mainwidget.h" -#include "messenger.h" +#include "core/application.h" #include "auth_session.h" #include "apiwrap.h" @@ -37,13 +38,13 @@ } const auto hash = match->captured(1); Auth().api().checkChatInvite(hash, [=](const MTPChatInvite &result) { - Messenger::Instance().hideMediaView(); + Core::App().hideMediaView(); result.match([=](const MTPDchatInvite &data) { Ui::show(Box(data, [=] { Auth().api().importChatInvite(hash); })); }, [=](const MTPDchatInviteAlready &data) { - if (const auto chat = App::feedChat(data.vchat)) { + if (const auto chat = Auth().data().processChat(data.vchat)) { App::wnd()->controller()->showPeerHistory( chat, Window::SectionShow::Way::Forward); @@ -53,7 +54,7 @@ if (error.code() != 400) { return; } - Messenger::Instance().hideMediaView(); + Core::App().hideMediaView(); Ui::show(Box(lang(lng_group_invite_bad_link))); }); return true; @@ -63,7 +64,7 @@ if (!AuthSession::Exists()) { return false; } - Messenger::Instance().hideMediaView(); + Core::App().hideMediaView(); Ui::show(Box( MTP_inputStickerSetShortName(MTP_string(match->captured(1))))); return true; @@ -172,7 +173,7 @@ qthelp::UrlParamNameTransform::ToLower); return BackgroundPreviewBox::Start( params.value(qsl("slug")), - params.value(qsl("mode"))); + params); } bool ResolveUsername(const Match &match, const QVariant &context) { @@ -309,4 +310,36 @@ return Result; } +bool InternalPassportLink(const QString &url) { + const auto urlTrimmed = url.trimmed(); + if (!urlTrimmed.startsWith(qstr("tg://"), Qt::CaseInsensitive)) { + return false; + } + const auto command = urlTrimmed.midRef(qstr("tg://").size()); + + using namespace qthelp; + const auto matchOptions = RegExOption::CaseInsensitive; + const auto authMatch = regex_match( + qsl("^passport/?\\?(.+)(#|$)"), + command, + matchOptions); + const auto usernameMatch = regex_match( + qsl("^resolve/?\\?(.+)(#|$)"), + command, + matchOptions); + const auto usernameValue = usernameMatch->hasMatch() + ? url_parse_params( + usernameMatch->captured(1), + UrlParamNameTransform::ToLower).value(qsl("domain")) + : QString(); + const auto authLegacy = (usernameValue == qstr("telegrampassport")); + return authMatch->hasMatch() || authLegacy; +} + +bool StartUrlRequiresActivate(const QString &url) { + return Core::App().locked() + ? true + : !InternalPassportLink(url); +} + } // namespace Core diff -Nru telegram-desktop-1.5.8/Telegram/SourceFiles/core/local_url_handlers.h telegram-desktop-1.5.11/Telegram/SourceFiles/core/local_url_handlers.h --- telegram-desktop-1.5.8/Telegram/SourceFiles/core/local_url_handlers.h 2019-01-21 17:28:45.000000000 +0000 +++ telegram-desktop-1.5.11/Telegram/SourceFiles/core/local_url_handlers.h 2019-02-01 12:51:46.000000000 +0000 @@ -22,4 +22,8 @@ const std::vector &LocalUrlHandlers(); +bool InternalPassportLink(const QString &url); + +bool StartUrlRequiresActivate(const QString &url); + } // namespace Core diff -Nru telegram-desktop-1.5.8/Telegram/SourceFiles/core/main_queue_processor.cpp telegram-desktop-1.5.11/Telegram/SourceFiles/core/main_queue_processor.cpp --- telegram-desktop-1.5.8/Telegram/SourceFiles/core/main_queue_processor.cpp 2019-01-21 17:28:45.000000000 +0000 +++ telegram-desktop-1.5.11/Telegram/SourceFiles/core/main_queue_processor.cpp 2019-02-01 12:51:46.000000000 +0000 @@ -7,7 +7,7 @@ */ #include "core/main_queue_processor.h" -#include "application.h" +#include "core/sandbox.h" namespace Core { namespace { @@ -54,12 +54,12 @@ if (ProcessorInstance) { const auto event = new ProcessorEvent(callable, argument); - QCoreApplication::postEvent(ProcessorInstance, event); + QApplication::postEvent(ProcessorInstance, event); } }); crl::wrap_main_queue([](void (*callable)(void*), void *argument) { - App().registerEnterFromEventLoop(); - const auto wrap = App().createEventNestingLevel(); + Sandbox::Instance().registerEnterFromEventLoop(); + const auto wrap = Sandbox::Instance().createEventNestingLevel(); callable(argument); }); diff -Nru telegram-desktop-1.5.8/Telegram/SourceFiles/core/sandbox.cpp telegram-desktop-1.5.11/Telegram/SourceFiles/core/sandbox.cpp --- telegram-desktop-1.5.8/Telegram/SourceFiles/core/sandbox.cpp 1970-01-01 00:00:00.000000000 +0000 +++ telegram-desktop-1.5.11/Telegram/SourceFiles/core/sandbox.cpp 2019-02-01 12:51:46.000000000 +0000 @@ -0,0 +1,581 @@ +/* +This file is part of Telegram Desktop, +the official desktop application for the Telegram messaging service. + +For license and copyright information please follow this link: +https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL +*/ +#include "core/sandbox.h" + +#include "platform/platform_specific.h" +#include "mainwidget.h" +#include "mainwindow.h" +#include "storage/localstorage.h" +#include "window/notifications_manager.h" +#include "core/crash_reports.h" +#include "core/application.h" +#include "core/launcher.h" +#include "core/local_url_handlers.h" +#include "base/timer.h" +#include "base/concurrent_timer.h" +#include "base/qthelp_url.h" +#include "base/qthelp_regex.h" +#include "core/update_checker.h" +#include "core/crash_report_window.h" + +namespace Core { +namespace { + +constexpr auto kEmptyPidForCommandResponse = 0ULL; + +using ErrorSignal = void(QLocalSocket::*)(QLocalSocket::LocalSocketError); +const auto QLocalSocket_error = ErrorSignal(&QLocalSocket::error); + +QChar _toHex(ushort v) { + v = v & 0x000F; + return QChar::fromLatin1((v >= 10) ? ('a' + (v - 10)) : ('0' + v)); +} +ushort _fromHex(QChar c) { + return ((c.unicode() >= uchar('a')) ? (c.unicode() - uchar('a') + 10) : (c.unicode() - uchar('0'))) & 0x000F; +} + +QString _escapeTo7bit(const QString &str) { + QString result; + result.reserve(str.size() * 2); + for (int i = 0, l = str.size(); i != l; ++i) { + QChar ch(str.at(i)); + ushort uch(ch.unicode()); + if (uch < 32 || uch > 127 || uch == ushort(uchar('%'))) { + result.append('%').append(_toHex(uch >> 12)).append(_toHex(uch >> 8)).append(_toHex(uch >> 4)).append(_toHex(uch)); + } else { + result.append(ch); + } + } + return result; +} + +QString _escapeFrom7bit(const QString &str) { + QString result; + result.reserve(str.size()); + for (int i = 0, l = str.size(); i != l; ++i) { + QChar ch(str.at(i)); + if (ch == QChar::fromLatin1('%') && i + 4 < l) { + result.append(QChar(ushort((_fromHex(str.at(i + 1)) << 12) | (_fromHex(str.at(i + 2)) << 8) | (_fromHex(str.at(i + 3)) << 4) | _fromHex(str.at(i + 4))))); + i += 4; + } else { + result.append(ch); + } + } + return result; +} + +} // namespace + +Sandbox::Sandbox( + not_null launcher, + int &argc, + char **argv) + : QApplication(argc, argv) + , _mainThreadId(QThread::currentThreadId()) + , _launcher(launcher) { +} + +int Sandbox::start() { + if (!Core::UpdaterDisabled()) { + _updateChecker = std::make_unique(); + } + const auto d = QFile::encodeName(QDir(cWorkingDir()).absolutePath()); + char h[33] = { 0 }; + hashMd5Hex(d.constData(), d.size(), h); +#ifndef OS_MAC_STORE + _localServerName = psServerPrefix() + h + '-' + cGUIDStr(); +#else // OS_MAC_STORE + h[4] = 0; // use only first 4 chars + _localServerName = psServerPrefix() + h; +#endif // OS_MAC_STORE + + connect( + &_localSocket, + &QLocalSocket::connected, + [=] { socketConnected(); }); + connect( + &_localSocket, + &QLocalSocket::disconnected, + [=] { socketDisconnected(); }); + connect( + &_localSocket, + QLocalSocket_error, + [=](QLocalSocket::LocalSocketError error) { socketError(error); }); + connect( + &_localSocket, + &QLocalSocket::bytesWritten, + [=](qint64 bytes) { socketWritten(bytes); }); + connect( + &_localSocket, + &QLocalSocket::readyRead, + [=] { socketReading(); }); + connect( + &_localServer, + &QLocalServer::newConnection, + [=] { newInstanceConnected(); }); + + crl::on_main(this, [=] { checkForQuit(); }); + connect( + this, + &QCoreApplication::aboutToQuit, + [=] { closeApplication(); }); + + if (cManyInstance()) { + LOG(("Many instance allowed, starting...")); + singleInstanceChecked(); + } else { + LOG(("Connecting local socket to %1...").arg(_localServerName)); + _localSocket.connectToServer(_localServerName); + } + + return exec(); +} + +void Sandbox::launchApplication() { + if (_application) { + return; + } + + const auto dpi = Sandbox::primaryScreen()->logicalDotsPerInch(); + LOG(("Primary screen DPI: %1").arg(dpi)); + if (dpi <= 108) { + cSetScreenScale(100); // 100%: 96 DPI (0-108) + } else if (dpi <= 132) { + cSetScreenScale(125); // 125%: 120 DPI (108-132) + } else if (dpi <= 168) { + cSetScreenScale(150); // 150%: 144 DPI (132-168) + } else if (dpi <= 216) { + cSetScreenScale(200); // 200%: 192 DPI (168-216) + } else if (dpi <= 264) { + cSetScreenScale(250); // 250%: 240 DPI (216-264) + } else { + cSetScreenScale(300); // 300%: 288 DPI (264-inf) + } + + const auto ratio = devicePixelRatio(); + if (ratio > 1.) { + if ((cPlatform() != dbipMac && cPlatform() != dbipMacOld) || (ratio != 2.)) { + LOG(("Found non-trivial Device Pixel Ratio: %1").arg(ratio)); + LOG(("Environmental variables: QT_DEVICE_PIXEL_RATIO='%1'").arg(QString::fromLatin1(qgetenv("QT_DEVICE_PIXEL_RATIO")))); + LOG(("Environmental variables: QT_SCALE_FACTOR='%1'").arg(QString::fromLatin1(qgetenv("QT_SCALE_FACTOR")))); + LOG(("Environmental variables: QT_AUTO_SCREEN_SCALE_FACTOR='%1'").arg(QString::fromLatin1(qgetenv("QT_AUTO_SCREEN_SCALE_FACTOR")))); + LOG(("Environmental variables: QT_SCREEN_SCALE_FACTORS='%1'").arg(QString::fromLatin1(qgetenv("QT_SCREEN_SCALE_FACTORS")))); + } + cSetRetinaFactor(ratio); + cSetIntRetinaFactor(int32(ratio)); + cSetScreenScale(kInterfaceScaleDefault); + } + + runApplication(); +} + +Sandbox::~Sandbox() = default; + +bool Sandbox::event(QEvent *e) { + if (e->type() == QEvent::Close) { + App::quit(); + } + return QApplication::event(e); +} + +void Sandbox::socketConnected() { + LOG(("Socket connected, this is not the first application instance, sending show command...")); + _secondInstance = true; + + QString commands; + const QStringList &lst(cSendPaths()); + for (QStringList::const_iterator i = lst.cbegin(), e = lst.cend(); i != e; ++i) { + commands += qsl("SEND:") + _escapeTo7bit(*i) + ';'; + } + if (!cStartUrl().isEmpty()) { + commands += qsl("OPEN:") + _escapeTo7bit(cStartUrl()) + ';'; + } else { + commands += qsl("CMD:show;"); + } + + DEBUG_LOG(("Sandbox Info: writing commands %1").arg(commands)); + _localSocket.write(commands.toLatin1()); +} + +void Sandbox::socketWritten(qint64/* bytes*/) { + if (_localSocket.state() != QLocalSocket::ConnectedState) { + LOG(("Socket is not connected %1").arg(_localSocket.state())); + return; + } + if (_localSocket.bytesToWrite()) { + return; + } + LOG(("Show command written, waiting response...")); +} + +void Sandbox::socketReading() { + if (_localSocket.state() != QLocalSocket::ConnectedState) { + LOG(("Socket is not connected %1").arg(_localSocket.state())); + return; + } + _localSocketReadData.append(_localSocket.readAll()); + if (QRegularExpression("RES:(\\d+);").match(_localSocketReadData).hasMatch()) { + uint64 pid = _localSocketReadData.mid(4, _localSocketReadData.length() - 5).toULongLong(); + if (pid != kEmptyPidForCommandResponse) { + psActivateProcess(pid); + } + LOG(("Show command response received, pid = %1, activating and quitting...").arg(pid)); + return App::quit(); + } +} + +void Sandbox::socketError(QLocalSocket::LocalSocketError e) { + if (App::quitting()) return; + + if (_secondInstance) { + LOG(("Could not write show command, error %1, quitting...").arg(e)); + return App::quit(); + } + + if (e == QLocalSocket::ServerNotFoundError) { + LOG(("This is the only instance of Telegram, starting server and app...")); + } else { + LOG(("Socket connect error %1, starting server and app...").arg(e)); + } + _localSocket.close(); + + // Local server does not work in WinRT build. +#ifndef Q_OS_WINRT + psCheckLocalSocket(_localServerName); + + if (!_localServer.listen(_localServerName)) { + LOG(("Failed to start listening to %1 server, error %2").arg(_localServerName).arg(int(_localServer.serverError()))); + return App::quit(); + } +#endif // !Q_OS_WINRT + + if (!Core::UpdaterDisabled() + && !cNoStartUpdate() + && Core::checkReadyUpdate()) { + cSetRestartingUpdate(true); + DEBUG_LOG(("Sandbox Info: installing update instead of starting app...")); + return App::quit(); + } + + singleInstanceChecked(); +} + +void Sandbox::singleInstanceChecked() { + if (cManyInstance()) { + Logs::multipleInstances(); + } + + refreshGlobalProxy(); + if (!Logs::started() || (!cManyInstance() && !Logs::instanceChecked())) { + new NotStartedWindow(); + return; + } + const auto result = CrashReports::Start(); + result.match([&](CrashReports::Status status) { + if (status == CrashReports::CantOpen) { + new NotStartedWindow(); + } else { + launchApplication(); + } + }, [&](const QByteArray &crashdump) { + // If crash dump is empty with that status it means that we + // didn't close the application properly. Just ignore for now. + if (crashdump.isEmpty()) { + if (CrashReports::Restart() == CrashReports::CantOpen) { + new NotStartedWindow(); + } else { + launchApplication(); + } + return; + } + _lastCrashDump = crashdump; + auto window = new LastCrashedWindow( + _launcher, + _lastCrashDump, + [=] { launchApplication(); }); + window->proxyChanges( + ) | rpl::start_with_next([=](ProxyData &&proxy) { + _sandboxProxy = std::move(proxy); + refreshGlobalProxy(); + }, window->lifetime()); + }); +} + +void Sandbox::socketDisconnected() { + if (_secondInstance) { + DEBUG_LOG(("Sandbox Error: socket disconnected before command response received, quitting...")); + return App::quit(); + } +} + +void Sandbox::newInstanceConnected() { + DEBUG_LOG(("Sandbox Info: new local socket connected")); + for (auto client = _localServer.nextPendingConnection(); client; client = _localServer.nextPendingConnection()) { + _localClients.push_back(LocalClient(client, QByteArray())); + connect( + client, + &QLocalSocket::readyRead, + [=] { readClients(); }); + connect( + client, + &QLocalSocket::disconnected, + [=] { removeClients(); }); + } +} + +void Sandbox::readClients() { + // This method can be called before Application is constructed. + QString startUrl; + QStringList toSend; + for (LocalClients::iterator i = _localClients.begin(), e = _localClients.end(); i != e; ++i) { + i->second.append(i->first->readAll()); + if (i->second.size()) { + QString cmds(QString::fromLatin1(i->second)); + int32 from = 0, l = cmds.length(); + for (int32 to = cmds.indexOf(QChar(';'), from); to >= from; to = (from < l) ? cmds.indexOf(QChar(';'), from) : -1) { + QStringRef cmd(&cmds, from, to - from); + if (cmd.startsWith(qsl("CMD:"))) { + execExternal(cmds.mid(from + 4, to - from - 4)); + const auto response = qsl("RES:%1;").arg(QApplication::applicationPid()).toLatin1(); + i->first->write(response.data(), response.size()); + } else if (cmd.startsWith(qsl("SEND:"))) { + if (cSendPaths().isEmpty()) { + toSend.append(_escapeFrom7bit(cmds.mid(from + 5, to - from - 5))); + } + } else if (cmd.startsWith(qsl("OPEN:"))) { + auto activateRequired = true; + if (cStartUrl().isEmpty()) { + startUrl = _escapeFrom7bit(cmds.mid(from + 5, to - from - 5)).mid(0, 8192); + activateRequired = StartUrlRequiresActivate(startUrl); + } + if (activateRequired) { + execExternal("show"); + } + const auto responsePid = activateRequired + ? QApplication::applicationPid() + : kEmptyPidForCommandResponse; + const auto response = qsl("RES:%1;").arg(responsePid).toLatin1(); + i->first->write(response.data(), response.size()); + } else { + LOG(("Sandbox Error: unknown command %1 passed in local socket").arg(QString(cmd.constData(), cmd.length()))); + } + from = to + 1; + } + if (from > 0) { + i->second = i->second.mid(from); + } + } + } + if (!toSend.isEmpty()) { + QStringList paths(cSendPaths()); + paths.append(toSend); + cSetSendPaths(paths); + } + if (!cSendPaths().isEmpty()) { + if (App::wnd()) { + App::wnd()->sendPaths(); + } + } + if (!startUrl.isEmpty()) { + cSetStartUrl(startUrl); + } + if (_application) { + _application->checkStartUrl(); + } +} + +void Sandbox::removeClients() { + DEBUG_LOG(("Sandbox Info: remove clients slot called, clients %1" + ).arg(_localClients.size())); + for (auto i = _localClients.begin(), e = _localClients.end(); i != e;) { + if (i->first->state() != QLocalSocket::ConnectedState) { + DEBUG_LOG(("Sandbox Info: removing client")); + i = _localClients.erase(i); + e = _localClients.end(); + } else { + ++i; + } + } +} + +void Sandbox::checkForQuit() { + if (App::quitting()) { + quit(); + } +} + +void Sandbox::runApplication() { + Expects(!App::quitting()); + + _application = std::make_unique(_launcher); + + // Ideally this should go to constructor. + // But we want to catch all native events and Application installs + // its own filter that can filter out some of them. So we install + // our filter after the Application constructor installs his. + installNativeEventFilter(this); + + _application->run(); +} + +void Sandbox::refreshGlobalProxy() { +#ifndef TDESKTOP_DISABLE_NETWORK_PROXY + const auto proxy = !Global::started() + ? _sandboxProxy + : (Global::ProxySettings() == ProxyData::Settings::Enabled) + ? Global::SelectedProxy() + : ProxyData(); + if (proxy.type == ProxyData::Type::Socks5 + || proxy.type == ProxyData::Type::Http) { + QNetworkProxy::setApplicationProxy( + ToNetworkProxy(ToDirectIpProxy(proxy))); + } else if (!Global::started() + || Global::ProxySettings() == ProxyData::Settings::System) { + QNetworkProxyFactory::setUseSystemConfiguration(true); + } else { + QNetworkProxy::setApplicationProxy(QNetworkProxy::NoProxy); + } +#endif // TDESKTOP_DISABLE_NETWORK_PROXY +} + +uint64 Sandbox::installationTag() const { + return _launcher->installationTag(); +} + +void Sandbox::postponeCall(FnMut &&callable) { + Expects(callable != nullptr); + Expects(_eventNestingLevel >= _loopNestingLevel); + + // _loopNestingLevel == _eventNestingLevel means that we had a + // native event in a nesting loop that didn't get a notify() call + // after. That means we already have exited the nesting loop and + // there must not be any postponed calls with that nesting level. + if (_loopNestingLevel == _eventNestingLevel) { + Assert(_postponedCalls.empty() + || _postponedCalls.back().loopNestingLevel < _loopNestingLevel); + Assert(!_previousLoopNestingLevels.empty()); + + _loopNestingLevel = _previousLoopNestingLevels.back(); + _previousLoopNestingLevels.pop_back(); + } + + _postponedCalls.push_back({ + _loopNestingLevel, + std::move(callable) + }); +} + +void Sandbox::incrementEventNestingLevel() { + ++_eventNestingLevel; +} + +void Sandbox::decrementEventNestingLevel() { + if (_eventNestingLevel == _loopNestingLevel) { + _loopNestingLevel = _previousLoopNestingLevels.back(); + _previousLoopNestingLevels.pop_back(); + } + const auto processTillLevel = _eventNestingLevel - 1; + processPostponedCalls(processTillLevel); + _eventNestingLevel = processTillLevel; +} + +void Sandbox::registerEnterFromEventLoop() { + if (_eventNestingLevel > _loopNestingLevel) { + _previousLoopNestingLevels.push_back(_loopNestingLevel); + _loopNestingLevel = _eventNestingLevel; + } +} + +bool Sandbox::notify(QObject *receiver, QEvent *e) { + if (QThread::currentThreadId() != _mainThreadId) { + return QApplication::notify(receiver, e); + } + + const auto wrap = createEventNestingLevel(); + return QApplication::notify(receiver, e); +} + +void Sandbox::processPostponedCalls(int level) { + while (!_postponedCalls.empty()) { + auto &last = _postponedCalls.back(); + if (last.loopNestingLevel != level) { + break; + } + auto taken = std::move(last); + _postponedCalls.pop_back(); + taken.callable(); + } +} + +bool Sandbox::nativeEventFilter( + const QByteArray &eventType, + void *message, + long *result) { + registerEnterFromEventLoop(); + return false; +} + +void Sandbox::activateWindowDelayed(not_null widget) { + if (_delayedActivationsPaused) { + return; + } else if (std::exchange(_windowForDelayedActivation, widget.get())) { + return; + } + crl::on_main(this, [=] { + if (const auto widget = base::take(_windowForDelayedActivation)) { + if (!widget->isHidden()) { + widget->activateWindow(); + } + } + }); +} + +void Sandbox::pauseDelayedWindowActivations() { + _windowForDelayedActivation = nullptr; + _delayedActivationsPaused = true; +} + +void Sandbox::resumeDelayedWindowActivations() { + _delayedActivationsPaused = false; +} + +ProxyData Sandbox::sandboxProxy() const { + return _sandboxProxy; +} + +void Sandbox::closeApplication() { + if (App::launchState() == App::QuitProcessed) { + return; + } + App::setLaunchState(App::QuitProcessed); + + _application = nullptr; + + _localServer.close(); + for (const auto &localClient : base::take(_localClients)) { + localClient.first->close(); + } + _localClients.clear(); + + _localSocket.close(); + + _updateChecker = nullptr; +} + +void Sandbox::execExternal(const QString &cmd) { + DEBUG_LOG(("Sandbox Info: executing external command '%1'").arg(cmd)); + if (cmd == "show") { + if (App::wnd()) { + App::wnd()->activate(); + } else if (PreLaunchWindow::instance()) { + PreLaunchWindow::instance()->activate(); + } + } +} + +} // namespace Core diff -Nru telegram-desktop-1.5.8/Telegram/SourceFiles/core/sandbox.h telegram-desktop-1.5.11/Telegram/SourceFiles/core/sandbox.h --- telegram-desktop-1.5.8/Telegram/SourceFiles/core/sandbox.h 1970-01-01 00:00:00.000000000 +0000 +++ telegram-desktop-1.5.11/Telegram/SourceFiles/core/sandbox.h 2019-02-01 12:51:46.000000000 +0000 @@ -0,0 +1,123 @@ +/* +This file is part of Telegram Desktop, +the official desktop application for the Telegram messaging service. + +For license and copyright information please follow this link: +https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL +*/ +#pragma once + +namespace Core { + +class Launcher; +class UpdateChecker; +class Application; + +class Sandbox final + : public QApplication + , private QAbstractNativeEventFilter { +public: + Sandbox(not_null launcher, int &argc, char **argv); + + Sandbox(const Sandbox &other) = delete; + Sandbox &operator=(const Sandbox &other) = delete; + + int start(); + + void refreshGlobalProxy(); + uint64 installationTag() const; + + void postponeCall(FnMut &&callable); + bool notify(QObject *receiver, QEvent *e) override; + void registerEnterFromEventLoop(); + auto createEventNestingLevel() { + incrementEventNestingLevel(); + return gsl::finally([=] { decrementEventNestingLevel(); }); + } + + void activateWindowDelayed(not_null widget); + void pauseDelayedWindowActivations(); + void resumeDelayedWindowActivations(); + + ProxyData sandboxProxy() const; + + static Sandbox &Instance() { + Expects(QApplication::instance() != nullptr); + + return *static_cast(QApplication::instance()); + } + + bool applicationLaunched() const { + return _application != nullptr; + } + Application &application() const { + Expects(_application != nullptr); + + return *_application; + } + + ~Sandbox(); + +protected: + bool event(QEvent *e) override; + +private: + typedef QPair LocalClient; + typedef QList LocalClients; + + struct PostponedCall { + int loopNestingLevel = 0; + FnMut callable; + }; + + void closeApplication(); // will be done in aboutToQuit() + void checkForQuit(); // will be done in exec() + void incrementEventNestingLevel(); + void decrementEventNestingLevel(); + bool nativeEventFilter( + const QByteArray &eventType, + void *message, + long *result) override; + void processPostponedCalls(int level); + void singleInstanceChecked(); + void launchApplication(); + void runApplication(); + void execExternal(const QString &cmd); + + // Single instance application + void socketConnected(); + void socketError(QLocalSocket::LocalSocketError e); + void socketDisconnected(); + void socketWritten(qint64 bytes); + void socketReading(); + void newInstanceConnected(); + + void readClients(); + void removeClients(); + + const Qt::HANDLE _mainThreadId = nullptr; + int _eventNestingLevel = 0; + int _loopNestingLevel = 0; + std::vector _previousLoopNestingLevels; + std::vector _postponedCalls; + + QPointer _windowForDelayedActivation; + bool _delayedActivationsPaused = false; + + not_null _launcher; + std::unique_ptr _application; + + QString _localServerName, _localSocketReadData; + QLocalServer _localServer; + QLocalSocket _localSocket; + LocalClients _localClients; + bool _secondInstance = false; + + std::unique_ptr _updateChecker; + + QByteArray _lastCrashDump; + ProxyData _sandboxProxy; + +}; + +} // namespace Core diff -Nru telegram-desktop-1.5.8/Telegram/SourceFiles/core/shortcuts.cpp telegram-desktop-1.5.11/Telegram/SourceFiles/core/shortcuts.cpp --- telegram-desktop-1.5.8/Telegram/SourceFiles/core/shortcuts.cpp 2019-01-21 17:28:45.000000000 +0000 +++ telegram-desktop-1.5.11/Telegram/SourceFiles/core/shortcuts.cpp 2019-02-01 12:51:46.000000000 +0000 @@ -9,7 +9,7 @@ #include "mainwindow.h" #include "mainwidget.h" -#include "messenger.h" +#include "core/application.h" #include "media/player/media_player_instance.h" #include "platform/platform_specific.h" #include "base/parse_helper.h" @@ -371,7 +371,7 @@ } auto shortcut = base::make_unique_q( result, - Messenger::Instance().getActiveWindow(), + Core::App().getActiveWindow(), nullptr, nullptr, Qt::ApplicationShortcut); diff -Nru telegram-desktop-1.5.8/Telegram/SourceFiles/core/update_checker.cpp telegram-desktop-1.5.11/Telegram/SourceFiles/core/update_checker.cpp --- telegram-desktop-1.5.8/Telegram/SourceFiles/core/update_checker.cpp 2019-01-21 17:28:45.000000000 +0000 +++ telegram-desktop-1.5.11/Telegram/SourceFiles/core/update_checker.cpp 2019-02-01 12:51:46.000000000 +0000 @@ -7,12 +7,12 @@ */ #include "core/update_checker.h" -#include "application.h" #include "platform/platform_specific.h" #include "base/timer.h" #include "base/bytes.h" #include "storage/localstorage.h" -#include "messenger.h" +#include "core/application.h" +#include "core/sandbox.h" #include "mainwindow.h" #include "core/click_handler_types.h" #include "info/info_memento.h" @@ -1129,9 +1129,10 @@ void Updater::handleReady() { stop(); _action = Action::Ready; - - cSetLastUpdateCheck(unixtime()); - Local::writeSettings(); + if (!App::quitting()) { + cSetLastUpdateCheck(unixtime()); + Local::writeSettings(); + } } void Updater::handleFailed() { @@ -1156,10 +1157,11 @@ void Updater::scheduleNext() { stop(); - - cSetLastUpdateCheck(unixtime()); - Local::writeSettings(); - start(true); + if (!App::quitting()) { + cSetLastUpdateCheck(unixtime()); + Local::writeSettings(); + start(true); + } } auto Updater::state() const -> State { @@ -1187,7 +1189,7 @@ } void Updater::start(bool forceWait) { - if (!Sandbox::started() || cExeName().isEmpty()) { + if (cExeName().isEmpty()) { return; } @@ -1382,8 +1384,8 @@ UpdateChecker::UpdateChecker() : _updater(GetUpdaterInstance()) { - if (const auto messenger = Messenger::InstancePointer()) { - if (const auto mtproto = messenger->mtp()) { + if (Sandbox::Instance().applicationLaunched()) { + if (const auto mtproto = Core::App().mtp()) { _updater->setMtproto(mtproto); } } @@ -1547,6 +1549,12 @@ return false; } #endif // Q_OS_LINUX + +#ifdef Q_OS_MAC + Platform::RemoveQuarantine(QFileInfo(curUpdater).absolutePath()); + Platform::RemoveQuarantine(updater.absolutePath()); +#endif // Q_OS_MAC + return true; } diff -Nru telegram-desktop-1.5.8/Telegram/SourceFiles/core/version.h telegram-desktop-1.5.11/Telegram/SourceFiles/core/version.h --- telegram-desktop-1.5.8/Telegram/SourceFiles/core/version.h 2019-01-21 17:28:45.000000000 +0000 +++ telegram-desktop-1.5.11/Telegram/SourceFiles/core/version.h 2019-02-01 12:51:46.000000000 +0000 @@ -15,7 +15,7 @@ #define TDESKTOP_ALPHA_VERSION (0ULL) #endif // TDESKTOP_OFFICIAL_TARGET -constexpr auto AppVersion = 1005008; -constexpr auto AppVersionStr = "1.5.8"; +constexpr auto AppVersion = 1005011; +constexpr auto AppVersionStr = "1.5.11"; constexpr auto AppBetaVersion = false; constexpr auto AppAlphaVersion = TDESKTOP_ALPHA_VERSION; diff -Nru telegram-desktop-1.5.8/Telegram/SourceFiles/data/data_channel_admins.cpp telegram-desktop-1.5.11/Telegram/SourceFiles/data/data_channel_admins.cpp --- telegram-desktop-1.5.8/Telegram/SourceFiles/data/data_channel_admins.cpp 2019-01-21 17:28:45.000000000 +0000 +++ telegram-desktop-1.5.11/Telegram/SourceFiles/data/data_channel_admins.cpp 2019-02-01 12:51:46.000000000 +0000 @@ -9,6 +9,7 @@ #include "history/history.h" #include "data/data_channel.h" +#include "data/data_session.h" namespace Data { @@ -29,7 +30,7 @@ ChannelAdminChanges::~ChannelAdminChanges() { if (!_changes.empty()) { - if (auto history = App::historyLoaded(_channel)) { + if (const auto history = _channel->owner().historyLoaded(_channel)) { history->applyGroupAdminChanges(_changes); } } diff -Nru telegram-desktop-1.5.8/Telegram/SourceFiles/data/data_channel.cpp telegram-desktop-1.5.11/Telegram/SourceFiles/data/data_channel.cpp --- telegram-desktop-1.5.8/Telegram/SourceFiles/data/data_channel.cpp 2019-01-21 17:28:45.000000000 +0000 +++ telegram-desktop-1.5.11/Telegram/SourceFiles/data/data_channel.cpp 2019-02-01 12:51:46.000000000 +0000 @@ -342,7 +342,9 @@ } bool ChannelData::canAddMembers() const { - return !amRestricted(ChatRestriction::f_invite_users); + return isMegagroup() + ? !amRestricted(ChatRestriction::f_invite_users) + : ((adminRights() & AdminRight::f_invite_users) || amCreator()); } bool ChannelData::canSendPolls() const { @@ -381,7 +383,9 @@ } bool ChannelData::canEditInformation() const { - return !amRestricted(Restriction::f_change_info); + return isMegagroup() + ? !amRestricted(Restriction::f_change_info) + : ((adminRights() & AdminRight::f_change_info) || amCreator()); } bool ChannelData::canEditPermissions() const { diff -Nru telegram-desktop-1.5.8/Telegram/SourceFiles/data/data_chat.cpp telegram-desktop-1.5.11/Telegram/SourceFiles/data/data_chat.cpp --- telegram-desktop-1.5.8/Telegram/SourceFiles/data/data_chat.cpp 2019-01-21 17:28:45.000000000 +0000 +++ telegram-desktop-1.5.11/Telegram/SourceFiles/data/data_chat.cpp 2019-02-01 12:51:46.000000000 +0000 @@ -39,10 +39,6 @@ } } -bool ChatData::actionsUnavailable() const { - return isDeactivated() || !amIn(); -} - auto ChatData::DefaultAdminRights() -> AdminRights { using Flag = AdminRight; return Flag::f_change_info @@ -54,17 +50,15 @@ bool ChatData::canWrite() const { // Duplicated in Data::CanWriteValue(). - return !actionsUnavailable() - && !amRestricted(Restriction::f_send_messages); + return amIn() && !amRestricted(Restriction::f_send_messages); } bool ChatData::canEditInformation() const { - return !actionsUnavailable() - && !amRestricted(Restriction::f_change_info); + return amIn() && !amRestricted(Restriction::f_change_info); } bool ChatData::canEditPermissions() const { - return !actionsUnavailable() + return amIn() && (amCreator() || (adminRights() & AdminRight::f_ban_users)); } @@ -78,18 +72,15 @@ } bool ChatData::canAddMembers() const { - return !actionsUnavailable() - && !amRestricted(Restriction::f_invite_users); + return amIn() && !amRestricted(Restriction::f_invite_users); } bool ChatData::canSendPolls() const { - return !actionsUnavailable() - && !amRestricted(Restriction::f_send_polls); + return amIn() && !amRestricted(Restriction::f_send_polls); } bool ChatData::canAddAdmins() const { - return !actionsUnavailable() - && amCreator(); + return amIn() && amCreator(); } bool ChatData::canBanMembers() const { diff -Nru telegram-desktop-1.5.8/Telegram/SourceFiles/data/data_chat.h telegram-desktop-1.5.11/Telegram/SourceFiles/data/data_chat.h --- telegram-desktop-1.5.8/Telegram/SourceFiles/data/data_chat.h 2019-01-21 17:28:45.000000000 +0000 +++ telegram-desktop-1.5.11/Telegram/SourceFiles/data/data_chat.h 2019-02-01 12:51:46.000000000 +0000 @@ -103,7 +103,10 @@ return flags() & MTPDchat_ClientFlag::f_forbidden; } bool amIn() const { - return !isForbidden() && !haveLeft() && !wasKicked(); + return !isForbidden() + && !isDeactivated() + && !haveLeft() + && !wasKicked(); } bool haveLeft() const { return flags() & MTPDchat::Flag::f_left; @@ -175,8 +178,6 @@ // ImagePtr photoFull; private: - [[nodiscard]] bool actionsUnavailable() const; - Flags _flags; FullFlags _fullFlags; QString _inviteLink; diff -Nru telegram-desktop-1.5.8/Telegram/SourceFiles/data/data_document.cpp telegram-desktop-1.5.11/Telegram/SourceFiles/data/data_document.cpp --- telegram-desktop-1.5.8/Telegram/SourceFiles/data/data_document.cpp 2019-01-21 17:28:45.000000000 +0000 +++ telegram-desktop-1.5.11/Telegram/SourceFiles/data/data_document.cpp 2019-02-01 12:51:46.000000000 +0000 @@ -25,9 +25,8 @@ #include "boxes/confirm_box.h" #include "ui/image/image.h" #include "ui/image/image_source.h" -#include "auth_session.h" #include "mainwindow.h" -#include "messenger.h" +#include "core/application.h" namespace { @@ -299,7 +298,7 @@ auto &location = data->location(true); if (data->isTheme()) { if (!location.isEmpty() && location.accessEnable()) { - Messenger::Instance().showDocument(data, context); + Core::App().showDocument(data, context); location.accessDisable(); return; } @@ -318,7 +317,7 @@ auto audio = AudioMsgId(data, msgId); Media::Player::mixer()->play(audio); Media::Player::Updated().notify(audio); - data->session()->data().markMediaRead(data); + data->owner().markMediaRead(data); } } else if (playMusic) { auto state = Media::Player::mixer()->currentState(AudioMsgId::Type::Song); @@ -335,9 +334,9 @@ } } else if (playVideo) { if (!data->data().isEmpty()) { - Messenger::Instance().showDocument(data, context); + Core::App().showDocument(data, context); } else if (location.accessEnable()) { - Messenger::Instance().showDocument(data, context); + Core::App().showDocument(data, context); location.accessDisable(); } else { const auto filepath = location.name(); @@ -345,26 +344,26 @@ File::Launch(filepath); } } - data->session()->data().markMediaRead(data); + data->owner().markMediaRead(data); } else if (data->isVoiceMessage() || data->isAudioFile() || data->isVideoFile()) { const auto filepath = location.name(); if (Data::IsValidMediaFile(filepath)) { File::Launch(filepath); } - data->session()->data().markMediaRead(data); + data->owner().markMediaRead(data); } else if (data->size < App::kImageSizeLimit) { if (!data->data().isEmpty() && playAnimation) { if (action == ActionOnLoadPlayInline && context) { - data->session()->data().requestAnimationPlayInline(context); + data->owner().requestAnimationPlayInline(context); } else { - Messenger::Instance().showDocument(data, context); + Core::App().showDocument(data, context); } } else if (location.accessEnable()) { if (playAnimation || QImageReader(location.name()).canRead()) { if (playAnimation && action == ActionOnLoadPlayInline && context) { - data->session()->data().requestAnimationPlayInline(context); + data->owner().requestAnimationPlayInline(context); } else { - Messenger::Instance().showDocument(data, context); + Core::App().showDocument(data, context); } } else { LaunchWithWarning(location.name(), context); @@ -462,13 +461,17 @@ } } -DocumentData::DocumentData(DocumentId id, not_null session) +DocumentData::DocumentData(not_null owner, DocumentId id) : id(id) -, _session(session) { +, _owner(owner) { } -not_null DocumentData::session() const { - return _session; +Data::Session &DocumentData::owner() const { + return *_owner; +} + +AuthSession &DocumentData::session() const { + return _owner->session(); } void DocumentData::setattributes(const QVector &attributes) { @@ -581,7 +584,7 @@ return true; } if (type != FileDocument - || !thumb + || !_thumbnail || !dimensions.width() || !dimensions.height() || dimensions.width() > Storage::kMaxWallPaperDimension @@ -590,13 +593,51 @@ return false; } type = WallPaperDocument; + validateGoodThumbnail(); return true; } +void DocumentData::updateThumbnails( + ImagePtr thumbnailInline, + ImagePtr thumbnail) { + if (thumbnailInline && !_thumbnailInline) { + _thumbnailInline = thumbnailInline; + } + if (thumbnail + && (!_thumbnail + || (sticker() + && (_thumbnail->width() < thumbnail->width() + || _thumbnail->height() < thumbnail->height())))) { + _thumbnail = thumbnail; + } +} + bool DocumentData::isWallPaper() const { return (type == WallPaperDocument); } +bool DocumentData::isPatternWallPaper() const { + return isWallPaper() && hasMimeType(qstr("image/png")); +} + +bool DocumentData::hasThumbnail() const { + return !_thumbnail->isNull(); +} + +Image *DocumentData::thumbnailInline() const { + return _thumbnailInline ? _thumbnailInline.get() : nullptr; +} + +Image *DocumentData::thumbnail() const { + return _thumbnail ? _thumbnail.get() : nullptr; +} + +void DocumentData::loadThumbnail(Data::FileOrigin origin) { + if (_thumbnail && !_thumbnail->loaded()) { + _thumbnail->load(origin); + } +} + Storage::Cache::Key DocumentData::goodThumbnailCacheKey() const { return Data::DocumentThumbCacheKey(_dc, id); } @@ -606,7 +647,7 @@ } void DocumentData::validateGoodThumbnail() { - if (!isVideoFile() && !isAnimation()) { + if (!isVideoFile() && !isAnimation() && !isWallPaper()) { _goodThumbnail = nullptr; } else if (!_goodThumbnail && hasRemoteLocation()) { _goodThumbnail = std::make_unique( @@ -645,14 +686,19 @@ void DocumentData::unload() { // Forget thumb only when image cache limit exceeds. - //thumb->unload(); + // + // Also, you can't unload() images that you don't own + // from the destructor, because they're already destroyed. + // + //_thumbnailInline->unload(); + //_thumbnail->unload(); if (sticker()) { if (sticker()->image) { ActiveCache().decrement(ComputeUsage(sticker())); sticker()->image = nullptr; } } - _replyPreview = nullptr; + _replyPreview.clear(); if (!_data.isEmpty()) { ActiveCache().decrement(_data.size()); _data.clear(); @@ -720,7 +766,7 @@ && item; if (auto applyTheme = isTheme()) { if (!loc.isEmpty() && loc.accessEnable()) { - Messenger::Instance().showDocument(this, item); + Core::App().showDocument(this, item); loc.accessDisable(); return; } @@ -737,7 +783,7 @@ } } else if (Media::Player::IsStopped(state.state)) { Media::Player::mixer()->play(AudioMsgId(this, _actionOnLoadMsgId)); - _session->data().markMediaRead(this); + _owner->markMediaRead(this); } } } else if (playMusic) { @@ -758,9 +804,9 @@ } else if (playAnimation) { if (loaded()) { if (_actionOnLoad == ActionOnLoadPlayInline && item) { - _session->data().requestAnimationPlayInline(item); + _owner->requestAnimationPlayInline(item); } else { - Messenger::Instance().showDocument(this, item); + Core::App().showDocument(this, item); } } } else { @@ -773,10 +819,10 @@ if (Data::IsValidMediaFile(already)) { File::Launch(already); } - _session->data().markMediaRead(this); + _owner->markMediaRead(this); } else if (loc.accessEnable()) { if (showImage && QImageReader(loc.name()).canRead()) { - Messenger::Instance().showDocument(this, item); + Core::App().showDocument(this, item); } else { LaunchWithWarning(already, item); } @@ -810,14 +856,14 @@ _loader->imageData())); ActiveCache().increment(ComputeUsage(that->sticker())); } - if (!that->_data.isEmpty() || that->getStickerImage()) { + if (!that->_data.isEmpty() || that->getStickerLarge()) { ActiveCache().up(that); } that->refreshGoodThumbnail(); destroyLoader(); } - _session->data().notifyDocumentLayoutChanged(this); + _owner->notifyDocumentLayoutChanged(this); } return !data().isEmpty() || !filepath(type).isEmpty(); } @@ -962,7 +1008,7 @@ if (loading()) { _loader->start(); } - _session->data().notifyDocumentLayoutChanged(this); + _owner->notifyDocumentLayoutChanged(this); } void DocumentData::cancel() { @@ -971,7 +1017,7 @@ } destroyLoader(CancelledMtpFileLoader); - _session->data().notifyDocumentLayoutChanged(this); + _owner->notifyDocumentLayoutChanged(this); App::main()->documentLoadProgress(this); _actionOnLoad = ActionOnLoadNone; @@ -1085,7 +1131,7 @@ Expects(sticker() != nullptr); const auto &set = sticker()->set; - const auto &sets = _session->data().stickerSets(); + const auto &sets = _owner->stickerSets(); switch (set.type()) { case mtpc_inputStickerSetID: { auto it = sets.constFind(set.c_inputStickerSetID().vid.v); @@ -1107,25 +1153,30 @@ } Image *DocumentData::getReplyPreview(Data::FileOrigin origin) { - if (!_replyPreview->isNull() && !thumb->isNull()) { - if (thumb->loaded()) { - int w = thumb->width(), h = thumb->height(); - if (w <= 0) w = 1; - if (h <= 0) h = 1; - auto thumbSize = (w > h) ? QSize(w * st::msgReplyBarSize.height() / h, st::msgReplyBarSize.height()) : QSize(st::msgReplyBarSize.height(), h * st::msgReplyBarSize.height() / w); - thumbSize *= cIntRetinaFactor(); - auto options = Images::Option::Smooth | (isVideoMessage() ? Images::Option::Circled : Images::Option::None) | Images::Option::TransparentBackground; - auto outerSize = st::msgReplyBarSize.height(); - auto image = thumb->pixNoCache(origin, thumbSize.width(), thumbSize.height(), options, outerSize, outerSize); - _replyPreview = std::make_unique( - std::make_unique( - image.toImage(), - "PNG")); - } else { - thumb->load(origin); + if (!_thumbnail) { + return nullptr; + } else if (_replyPreview + && (_replyPreview.good() || !_thumbnail->loaded())) { + return _replyPreview.image(); + } + const auto option = isVideoMessage() + ? Images::Option::Circled + : Images::Option::None; + if (_thumbnail->loaded()) { + _replyPreview.prepare( + _thumbnail.get(), + origin, + option); + } else { + _thumbnail->load(origin); + if (_thumbnailInline) { + _replyPreview.prepare( + _thumbnailInline.get(), + origin, + option | Images::Option::Blurred); } } - return _replyPreview.get(); + return _replyPreview.image(); } StickerData *DocumentData::sticker() const { @@ -1134,7 +1185,7 @@ : nullptr; } -void DocumentData::checkSticker() { +void DocumentData::checkStickerLarge() { const auto data = sticker(); if (!data) return; @@ -1164,25 +1215,25 @@ } } -void DocumentData::checkStickerThumb() { - if (hasGoodStickerThumb()) { - thumb->load(stickerSetOrigin()); +void DocumentData::checkStickerSmall() { + if (thumbnailEnoughForSticker()) { + _thumbnail->load(stickerSetOrigin()); } else { - checkSticker(); + checkStickerLarge(); } } -Image *DocumentData::getStickerImage() { - checkSticker(); +Image *DocumentData::getStickerLarge() { + checkStickerLarge(); if (const auto data = sticker()) { return data->image.get(); } return nullptr; } -Image *DocumentData::getStickerThumb() { - if (hasGoodStickerThumb()) { - return thumb->isNull() ? nullptr : thumb.get(); +Image *DocumentData::getStickerSmall() { + if (thumbnailEnoughForSticker()) { + return _thumbnail->isNull() ? nullptr : _thumbnail.get(); } else if (const auto data = sticker()) { return data->image.get(); } @@ -1236,8 +1287,8 @@ return _urlLocation.dc() != 0 && _urlLocation.accessHash() != 0; } -bool DocumentData::isValid() const { - return hasRemoteLocation() || hasWebLocation() || !_url.isEmpty(); +bool DocumentData::isNull() const { + return !hasRemoteLocation() && !hasWebLocation() && _url.isEmpty(); } MTPInputDocument DocumentData::mtpInput() const { @@ -1260,9 +1311,9 @@ void DocumentData::refreshStickerThumbFileReference() { if (const auto data = sticker()) { - if (thumb->loading()) { + if (_thumbnail->loading()) { data->loc.refreshFileReference( - thumb->location().fileReference()); + _thumbnail->location().fileReference()); } } } @@ -1407,9 +1458,9 @@ && fileIsImage(filename(), mimeString()); } -bool DocumentData::hasGoodStickerThumb() const { - return !thumb->isNull() - && ((thumb->width() >= 128) || (thumb->height() >= 128)); +bool DocumentData::thumbnailEnoughForSticker() const { + return !_thumbnail->isNull() + && ((_thumbnail->width() >= 128) || (_thumbnail->height() >= 128)); } void DocumentData::setRemoteLocation( @@ -1420,7 +1471,7 @@ if (_dc != dc || _access != access) { _dc = dc; _access = access; - if (isValid()) { + if (!isNull()) { if (_location.check()) { Local::writeFileLocation(mediaKey(), _location); } else { @@ -1439,10 +1490,12 @@ _urlLocation = location; } -void DocumentData::collectLocalData(DocumentData *local) { - if (local == this) return; +void DocumentData::collectLocalData(not_null local) { + if (local == this) { + return; + } - _session->data().cache().copyIfEmpty(local->cacheKey(), cacheKey()); + _owner->cache().copyIfEmpty(local->cacheKey(), cacheKey()); if (!local->_data.isEmpty()) { ActiveCache().decrement(_data.size()); _data = local->_data; @@ -1516,13 +1569,22 @@ static const auto kExtensions = [] { const auto joined = #ifdef Q_OS_MAC - qsl("action app bin command csh osx workflow terminal"); + qsl("\ +action app bin command csh osx workflow terminal url caction mpkg pkg xhtm \ +webarchive"); #elif defined Q_OS_LINUX // Q_OS_MAC - qsl("bin csh ksh out run"); + qsl("bin csh deb desktop ksh out pet pkg pup rpm run shar slp"); #else // Q_OS_MAC || Q_OS_LINUX qsl("\ -bat bin cmd com cpl exe gadget inf ins inx isu job jse lnk msc msi msp mst \ -paf pif ps1 reg rgs scr sct shb shs u3p vb vbe vbs vbscript ws wsf"); +ad ade adp app application appref-ms asp asx bas bat bin cer cfg chi chm \ +cmd cnt com cpl crt csh der diagcab dll drv eml exe fon fxp gadget grp hlp \ +hpj hta htt inf ini ins inx isp isu its jar jnlp job js jse ksh lnk local \ +mad maf mag mam manifest maq mar mas mat mau mav maw mcf mda mdb mde mdt \ +mdw mdz mht mhtml mmc mof msc msg msh msh1 msh2 msh1xml msh2xml mshxml msi \ +msp mst ops osd paf pcd pif pl plg prf prg ps1 ps2 ps1xml ps2xml psc1 psc2 \ +pst reg rgs scf scr sct search-ms settingcontent-ms shb shs slk sys tmp \ +u3p url vb vbe vbp vbs vbscript vdx vsmacros vsd vsdm vsdx vss vssm vssx \ +vst vstm vstx vsw vsx vtx website ws wsc wsf wsh xbap xll xnk"); #endif // !Q_OS_MAC && !Q_OS_LINUX const auto list = joined.split(' '); return base::flat_set(list.begin(), list.end()); diff -Nru telegram-desktop-1.5.8/Telegram/SourceFiles/data/data_document_good_thumbnail.cpp telegram-desktop-1.5.11/Telegram/SourceFiles/data/data_document_good_thumbnail.cpp --- telegram-desktop-1.5.8/Telegram/SourceFiles/data/data_document_good_thumbnail.cpp 2019-01-21 17:28:45.000000000 +0000 +++ telegram-desktop-1.5.11/Telegram/SourceFiles/data/data_document_good_thumbnail.cpp 2019-02-01 12:51:46.000000000 +0000 @@ -17,6 +17,41 @@ namespace { constexpr auto kGoodThumbQuality = 87; +constexpr auto kWallPaperSize = 960; + +QImage Prepare( + const QString &path, + QByteArray data, + bool isWallPaper) { + if (!isWallPaper) { + return Media::Clip::PrepareForSending(path, data).thumbnail; + } + const auto validateSize = [](QSize size) { + return (size.width() + size.height()) < 10'000; + }; + auto buffer = QBuffer(&data); + auto file = QFile(path); + auto device = data.isEmpty() ? static_cast(&file) : &buffer; + auto reader = QImageReader(device); +#ifndef OS_MAC_OLD + reader.setAutoTransform(true); +#endif // OS_MAC_OLD + if (!reader.canRead() || !validateSize(reader.size())) { + return QImage(); + } + auto result = reader.read(); + if (!result.width() || !result.height()) { + return QImage(); + } + return (result.width() > kWallPaperSize + || result.height() > kWallPaperSize) + ? result.scaled( + kWallPaperSize, + kWallPaperSize, + Qt::KeepAspectRatio, + Qt::SmoothTransformation) + : result; +} } // namespace @@ -29,6 +64,7 @@ return; } const auto data = _document->data(); + const auto isWallPaper = _document->isWallPaper(); auto location = _document->location().isEmpty() ? nullptr : std::make_unique(_document->location()); @@ -44,11 +80,14 @@ const auto filepath = (location && location->accessEnable()) ? location->name() : QString(); - auto result = Media::Clip::PrepareForSending(filepath, data); + auto result = Prepare(filepath, data, isWallPaper); auto bytes = QByteArray(); - if (!result.thumbnail.isNull()) { - QBuffer buffer(&bytes); - result.thumbnail.save(&buffer, "JPG", kGoodThumbQuality); + if (!result.isNull()) { + auto buffer = QBuffer(&bytes); + const auto format = (isWallPaper && result.hasAlphaChannel()) + ? "PNG" + : "JPG"; + result.save(&buffer, format, kGoodThumbQuality); } if (!filepath.isEmpty()) { location->accessDisable(); @@ -56,7 +95,7 @@ const auto bytesSize = bytes.size(); ready( std::move(guard), - std::move(result.thumbnail), + std::move(result), bytesSize, std::move(bytes)); }); @@ -119,7 +158,10 @@ guard = std::move(guard), value = std::move(value) ]() mutable { - ready(std::move(guard), App::readImage(value), value.size()); + ready( + std::move(guard), + App::readImage(value, nullptr, false), + value.size()); }); }; diff -Nru telegram-desktop-1.5.8/Telegram/SourceFiles/data/data_document.h telegram-desktop-1.5.11/Telegram/SourceFiles/data/data_document.h --- telegram-desktop-1.5.8/Telegram/SourceFiles/data/data_document.h 2019-01-21 17:28:45.000000000 +0000 +++ telegram-desktop-1.5.11/Telegram/SourceFiles/data/data_document.h 2019-02-01 12:51:46.000000000 +0000 @@ -8,6 +8,7 @@ #pragma once #include "data/data_types.h" +#include "ui/image/image.h" namespace Images { class Source; @@ -19,6 +20,10 @@ } // namespace Cache } // namespace Storage +namespace Data { +class Session; +} // namespace Data + class AuthSession; class mtpFileLoader; @@ -75,9 +80,10 @@ class DocumentData { public: - DocumentData(DocumentId id, not_null session); + DocumentData(not_null owner, DocumentId id); - not_null session() const; + [[nodiscard]] Data::Session &owner() const; + [[nodiscard]] AuthSession &session() const; void setattributes( const QVector &attributes); @@ -93,11 +99,11 @@ FilePathResolveSaveFromData, FilePathResolveSaveFromDataSilent, }; - bool loaded( + [[nodiscard]] bool loaded( FilePathResolveType type = FilePathResolveCached) const; - bool loading() const; - QString loadingFilePath() const; - bool displayLoading() const; + [[nodiscard]] bool loading() const; + [[nodiscard]] QString loadingFilePath() const; + [[nodiscard]] bool displayLoading() const; void save( Data::FileOrigin origin, const QString &toFile, @@ -106,19 +112,19 @@ LoadFromCloudSetting fromCloud = LoadFromCloudOrLocal, bool autoLoading = false); void cancel(); - bool cancelled() const; - float64 progress() const; - int32 loadOffset() const; - bool uploading() const; + [[nodiscard]] bool cancelled() const; + [[nodiscard]] float64 progress() const; + [[nodiscard]] int32 loadOffset() const; + [[nodiscard]] bool uploading() const; void setWaitingForAlbum(); - bool waitingForAlbum() const; + [[nodiscard]] bool waitingForAlbum() const; - QByteArray data() const; - const FileLocation &location(bool check = false) const; + [[nodiscard]] QByteArray data() const; + [[nodiscard]] const FileLocation &location(bool check = false) const; void setLocation(const FileLocation &loc); - QString filepath( + [[nodiscard]] QString filepath( FilePathResolveType type = FilePathResolveCached, bool forceSavingAs = false) const; @@ -127,44 +133,51 @@ void performActionOnLoad(); void unload(); - Image *getReplyPreview(Data::FileOrigin origin); + [[nodiscard]] Image *getReplyPreview(Data::FileOrigin origin); - StickerData *sticker() const; - void checkSticker(); - void checkStickerThumb(); - Image *getStickerThumb(); - Image *getStickerImage(); - Data::FileOrigin stickerSetOrigin() const; - Data::FileOrigin stickerOrGifOrigin() const; - bool isStickerSetInstalled() const; - SongData *song(); - const SongData *song() const; - VoiceData *voice(); - const VoiceData *voice() const; - - bool isVoiceMessage() const; - bool isVideoMessage() const; - bool isSong() const; - bool isAudioFile() const; - bool isVideoFile() const; - bool isAnimation() const; - bool isGifv() const; - bool isTheme() const; - bool isSharedMediaMusic() const; - int32 duration() const; - bool isImage() const; + [[nodiscard]] StickerData *sticker() const; + void checkStickerLarge(); + void checkStickerSmall(); + [[nodiscard]] Image *getStickerSmall(); + [[nodiscard]] Image *getStickerLarge(); + [[nodiscard]] Data::FileOrigin stickerSetOrigin() const; + [[nodiscard]] Data::FileOrigin stickerOrGifOrigin() const; + [[nodiscard]] bool isStickerSetInstalled() const; + [[nodiscard]] SongData *song(); + [[nodiscard]] const SongData *song() const; + [[nodiscard]] VoiceData *voice(); + [[nodiscard]] const VoiceData *voice() const; + + [[nodiscard]] bool isVoiceMessage() const; + [[nodiscard]] bool isVideoMessage() const; + [[nodiscard]] bool isSong() const; + [[nodiscard]] bool isAudioFile() const; + [[nodiscard]] bool isVideoFile() const; + [[nodiscard]] bool isAnimation() const; + [[nodiscard]] bool isGifv() const; + [[nodiscard]] bool isTheme() const; + [[nodiscard]] bool isSharedMediaMusic() const; + [[nodiscard]] int32 duration() const; + [[nodiscard]] bool isImage() const; void recountIsImage(); - bool supportsStreaming() const; + [[nodiscard]] bool supportsStreaming() const; void setData(const QByteArray &data) { _data = data; } bool checkWallPaperProperties(); - bool isWallPaper() const; + [[nodiscard]] bool isWallPaper() const; + [[nodiscard]] bool isPatternWallPaper() const; - bool hasGoodStickerThumb() const; + [[nodiscard]] bool hasThumbnail() const; + void loadThumbnail(Data::FileOrigin origin); + [[nodiscard]] Image *thumbnailInline() const; + [[nodiscard]] Image *thumbnail() const; + void updateThumbnails( + ImagePtr thumbnailInline, + ImagePtr thumbnail); - Image *goodThumbnail() const; - Storage::Cache::Key goodThumbnailCacheKey() const; + [[nodiscard]] Image *goodThumbnail() const; + [[nodiscard]] Storage::Cache::Key goodThumbnailCacheKey() const; void setGoodThumbnail(QImage &&image, QByteArray &&bytes); void refreshGoodThumbnail(); void replaceGoodThumbnail(std::unique_ptr &&source); @@ -175,11 +188,11 @@ const QByteArray &fileReference); void setContentUrl(const QString &url); void setWebLocation(const WebFileLocation &location); - bool hasRemoteLocation() const; - bool hasWebLocation() const; - bool isValid() const; - MTPInputDocument mtpInput() const; - QByteArray fileReference() const; + [[nodiscard]] bool hasRemoteLocation() const; + [[nodiscard]] bool hasWebLocation() const; + [[nodiscard]] bool isNull() const; + [[nodiscard]] MTPInputDocument mtpInput() const; + [[nodiscard]] QByteArray fileReference() const; void refreshFileReference(const QByteArray &value); void refreshStickerThumbFileReference(); @@ -187,22 +200,22 @@ // (for example for displaying an external inline bot result) // and it has downloaded data, we can collect that data from it // to (this) received from the server "same" document. - void collectLocalData(DocumentData *local); + void collectLocalData(not_null local); - QString filename() const; - QString mimeString() const; - bool hasMimeType(QLatin1String mime) const; + [[nodiscard]] QString filename() const; + [[nodiscard]] QString mimeString() const; + [[nodiscard]] bool hasMimeType(QLatin1String mime) const; void setMimeString(const QString &mime); - MediaKey mediaKey() const; - Storage::Cache::Key cacheKey() const; - uint8 cacheTag() const; + [[nodiscard]] MediaKey mediaKey() const; + [[nodiscard]] Storage::Cache::Key cacheKey() const; + [[nodiscard]] uint8 cacheTag() const; - static QString ComposeNameString( + [[nodiscard]] static QString ComposeNameString( const QString &filename, const QString &songTitle, const QString &songPerformer); - QString composeNameString() const; + [[nodiscard]] QString composeNameString() const; ~DocumentData(); @@ -210,7 +223,6 @@ DocumentType type = FileDocument; QSize dimensions; int32 date = 0; - ImagePtr thumb; int32 size = 0; FileStatus status = FileReady; @@ -225,6 +237,8 @@ void destroyLoader(mtpFileLoader *newValue = nullptr) const; + [[nodiscard]] bool thumbnailEnoughForSticker() const; + // Two types of location: from MTProto by dc+access or from web by url int32 _dc = 0; uint64 _access = 0; @@ -234,10 +248,12 @@ QString _mimeString; WebFileLocation _urlLocation; + ImagePtr _thumbnailInline; + ImagePtr _thumbnail; std::unique_ptr _goodThumbnail; - std::unique_ptr _replyPreview; + Data::ReplyPreview _replyPreview; - not_null _session; + not_null _owner; FileLocation _location; QByteArray _data; @@ -327,6 +343,26 @@ }; +class DocumentWrappedClickHandler : public DocumentClickHandler { +public: + DocumentWrappedClickHandler( + ClickHandlerPtr wrapped, + not_null document, + FullMsgId context = FullMsgId()) + : DocumentClickHandler(document, context) + , _wrapped(wrapped) { + } + +protected: + void onClickImpl() const override { + _wrapped->onClick({ Qt::LeftButton }); + } + +private: + ClickHandlerPtr _wrapped; + +}; + QString FileNameForSave( const QString &title, const QString &filter, diff -Nru telegram-desktop-1.5.8/Telegram/SourceFiles/data/data_drafts.cpp telegram-desktop-1.5.11/Telegram/SourceFiles/data/data_drafts.cpp --- telegram-desktop-1.5.8/Telegram/SourceFiles/data/data_drafts.cpp 2019-01-21 17:28:45.000000000 +0000 +++ telegram-desktop-1.5.11/Telegram/SourceFiles/data/data_drafts.cpp 2019-02-01 12:51:46.000000000 +0000 @@ -11,6 +11,7 @@ #include "chat_helpers/message_field.h" #include "history/history.h" #include "history/history_widget.h" +#include "data/data_session.h" #include "mainwidget.h" #include "storage/localstorage.h" #include "support/support_helper.h" @@ -45,7 +46,7 @@ } void applyPeerCloudDraft(PeerId peerId, const MTPDdraftMessage &draft) { - const auto history = App::history(peerId); + const auto history = Auth().data().history(peerId); const auto textWithTags = TextWithTags { qs(draft.vmessage), ConvertEntitiesToTextTags( @@ -79,7 +80,7 @@ } void clearPeerCloudDraft(PeerId peerId, TimeId date) { - const auto history = App::history(peerId); + const auto history = Auth().data().history(peerId); if (history->skipCloudDraft(QString(), MsgId(0), date)) { return; } diff -Nru telegram-desktop-1.5.8/Telegram/SourceFiles/data/data_feed.cpp telegram-desktop-1.5.11/Telegram/SourceFiles/data/data_feed.cpp --- telegram-desktop-1.5.8/Telegram/SourceFiles/data/data_feed.cpp 2019-01-21 17:28:45.000000000 +0000 +++ telegram-desktop-1.5.11/Telegram/SourceFiles/data/data_feed.cpp 2019-02-01 12:51:46.000000000 +0000 @@ -78,7 +78,7 @@ } void Feed::registerOne(not_null channel) { - const auto history = App::history(channel); + const auto history = owner().history(channel); if (!base::contains(_channels, history)) { const auto invisible = (_channels.size() < 2); _channels.push_back(history); @@ -120,7 +120,7 @@ } void Feed::unregisterOne(not_null channel) { - const auto history = App::history(channel); + const auto history = owner().history(channel); const auto i = ranges::remove(_channels, history); if (i != end(_channels)) { const auto visible = (_channels.size() > 1); @@ -339,7 +339,7 @@ // #feed //void Feed::applyDialog(const MTPDdialogFeed &data) { // const auto addChannel = [&](ChannelId channelId) { -// if (const auto channel = App::channelLoaded(channelId)) { +// if (const auto channel = owner().channelLoaded(channelId)) { // channel->setFeed(this); // } // }; diff -Nru telegram-desktop-1.5.8/Telegram/SourceFiles/data/data_media_types.cpp telegram-desktop-1.5.11/Telegram/SourceFiles/data/data_media_types.cpp --- telegram-desktop-1.5.8/Telegram/SourceFiles/data/data_media_types.cpp 2019-01-21 17:28:45.000000000 +0000 +++ telegram-desktop-1.5.11/Telegram/SourceFiles/data/data_media_types.cpp 2019-02-01 12:51:46.000000000 +0000 @@ -290,7 +290,7 @@ } bool MediaPhoto::hasReplyPreview() const { - return !_photo->thumb->isNull(); + return !_photo->isNull(); } Image *MediaPhoto::replyPreview() const { @@ -338,7 +338,8 @@ } auto &data = media.c_messageMediaPhoto(); if (data.has_photo() && !data.has_ttl_seconds()) { - const auto photo = parent()->history()->owner().photo(data.vphoto); + const auto photo = parent()->history()->owner().processPhoto( + data.vphoto); if (photo == _photo) { return true; } else { @@ -377,7 +378,7 @@ QByteArray bytes; }; const auto saveImageToCache = [&]( - const ImagePtr &image, + not_null image, SizeData size) { Expects(size.location != nullptr); @@ -434,9 +435,9 @@ continue; } if (size.letter == 's') { - saveImageToCache(_photo->thumb, size); + saveImageToCache(_photo->thumbnailSmall(), size); } else if (size.letter == 'm') { - saveImageToCache(_photo->medium, size); + saveImageToCache(_photo->thumbnail(), size); } else if (size.letter == 'x' && max < 1) { max = 1; maxSize = size; @@ -449,7 +450,7 @@ } } if (maxSize.location) { - saveImageToCache(_photo->full, maxSize); + saveImageToCache(_photo->large(), maxSize); } return true; } @@ -532,7 +533,7 @@ } bool MediaFile::hasReplyPreview() const { - return !_document->thumb->isNull(); + return _document->hasThumbnail(); } Image *MediaFile::replyPreview() const { @@ -684,7 +685,7 @@ } auto &data = media.c_messageMediaDocument(); if (data.has_document() && !data.has_ttl_seconds()) { - const auto document = parent()->history()->owner().document( + const auto document = parent()->history()->owner().processDocument( data.vdocument); if (document == _document) { return false; @@ -1016,9 +1017,9 @@ bool MediaWebPage::hasReplyPreview() const { if (const auto document = MediaWebPage::document()) { - return !document->thumb->isNull(); + return document->hasThumbnail() && !document->isPatternWallPaper(); } else if (const auto photo = MediaWebPage::photo()) { - return !photo->thumb->isNull(); + return !photo->isNull(); } return false; } @@ -1079,9 +1080,9 @@ bool MediaGame::hasReplyPreview() const { if (const auto document = _game->document) { - return !document->thumb->isNull(); + return document->hasThumbnail(); } else if (const auto photo = _game->photo) { - return !photo->thumb->isNull(); + return !photo->isNull(); } return false; } @@ -1181,7 +1182,7 @@ bool MediaInvoice::hasReplyPreview() const { if (const auto photo = _invoice.photo) { - return !photo->thumb->isNull(); + return !photo->isNull(); } return false; } diff -Nru telegram-desktop-1.5.8/Telegram/SourceFiles/data/data_peer.cpp telegram-desktop-1.5.11/Telegram/SourceFiles/data/data_peer.cpp --- telegram-desktop-1.5.8/Telegram/SourceFiles/data/data_peer.cpp 2019-01-21 17:28:45.000000000 +0000 +++ telegram-desktop-1.5.11/Telegram/SourceFiles/data/data_peer.cpp 2019-02-01 12:51:46.000000000 +0000 @@ -20,7 +20,7 @@ #include "apiwrap.h" #include "boxes/confirm_box.h" #include "auth_session.h" -#include "messenger.h" +#include "core/application.h" #include "mainwindow.h" #include "window/window_controller.h" #include "ui/image/image.h" @@ -179,7 +179,7 @@ void PeerData::setUserpicPhoto(const MTPPhoto &data) { const auto photoId = data.match([&](const MTPDphoto &data) { - const auto photo = owner().photo(data); + const auto photo = owner().processPhoto(data); photo->peer = this; return photo->id; }, [](const MTPDphotoEmpty &data) { @@ -315,7 +315,7 @@ const auto loc = StorageImageLocation(); const auto photo = [&] { if (id == peerFromUser(ServiceUserId)) { - auto image = Messenger::Instance().logoNoMargin().scaledToWidth( + auto image = Core::App().logoNoMargin().scaledToWidth( kUserpicSize, Qt::SmoothTransformation); return _userpic @@ -350,16 +350,12 @@ if (const auto user = asUser()) { return user->fullFlags() & MTPDuserFull::Flag::f_can_pin_message; } else if (const auto chat = asChat()) { - return !chat->isDeactivated() - && ((chat->adminRights() & ChatAdminRight::f_pin_messages) - || chat->amCreator()); + return chat->amIn() && !chat->amRestricted(ChatRestriction::f_pin_messages); } else if (const auto channel = asChannel()) { - if (channel->isMegagroup()) { - return (channel->adminRights() & ChatAdminRight::f_pin_messages) - || channel->amCreator(); - } - return (channel->adminRights() & ChatAdminRight::f_edit_messages) - || channel->amCreator(); + return channel->isMegagroup() + ? !channel->amRestricted(ChatRestriction::f_pin_messages) + : ((channel->adminRights() & ChatAdminRight::f_edit_messages) + || channel->amCreator()); } Unexpected("Peer type in PeerData::canPinMessages."); } @@ -613,9 +609,13 @@ } }; if (const auto channel = asChannel()) { + const auto defaultRestrictions = channel->defaultRestrictions() + | (channel->isPublic() + ? (ChatRestriction::f_pin_messages | ChatRestriction::f_change_info) + : ChatRestrictions(0)); return (channel->amCreator() || allowByAdminRights(right, channel)) ? Result::Allowed() - : (channel->defaultRestrictions() & right) + : (defaultRestrictions & right) ? Result::WithEveryone() : (channel->restrictions() & right) ? Result::Explicit() diff -Nru telegram-desktop-1.5.8/Telegram/SourceFiles/data/data_peer_values.cpp telegram-desktop-1.5.11/Telegram/SourceFiles/data/data_peer_values.cpp --- telegram-desktop-1.5.8/Telegram/SourceFiles/data/data_peer_values.cpp 2019-01-21 17:28:45.000000000 +0000 +++ telegram-desktop-1.5.11/Telegram/SourceFiles/data/data_peer_values.cpp 2019-02-01 12:51:46.000000000 +0000 @@ -189,12 +189,12 @@ MTPDchat::Flags flags, Data::Flags::Change adminRights, bool defaultSendMessagesRestriction) { - const auto actionsUnavailableFlags = 0 + const auto amOutFlags = 0 | MTPDchat::Flag::f_deactivated | MTPDchat_ClientFlag::f_forbidden | MTPDchat::Flag::f_left | MTPDchat::Flag::f_kicked; - return !(flags & actionsUnavailableFlags) + return !(flags & amOutFlags) && ((flags & MTPDchat::Flag::f_creator) || (adminRights.value != MTPDchatAdminRights::Flags(0)) || !defaultSendMessagesRestriction); diff -Nru telegram-desktop-1.5.8/Telegram/SourceFiles/data/data_photo.cpp telegram-desktop-1.5.11/Telegram/SourceFiles/data/data_photo.cpp --- telegram-desktop-1.5.8/Telegram/SourceFiles/data/data_photo.cpp 2019-01-21 17:28:45.000000000 +0000 +++ telegram-desktop-1.5.11/Telegram/SourceFiles/data/data_photo.cpp 2019-02-01 12:51:46.000000000 +0000 @@ -12,49 +12,41 @@ #include "ui/image/image.h" #include "ui/image/image_source.h" #include "mainwidget.h" -#include "auth_session.h" -#include "messenger.h" +#include "core/application.h" -PhotoData::PhotoData(const PhotoId &id) -: id(id) { +PhotoData::PhotoData(not_null owner, PhotoId id) +: id(id) +, _owner(owner) { } -PhotoData::PhotoData( - const PhotoId &id, - const uint64 &access, - const QByteArray &fileReference, - TimeId date, - const ImagePtr &thumb, - const ImagePtr &medium, - const ImagePtr &full) -: id(id) -, access(access) -, date(date) -, thumb(thumb) -, medium(medium) -, full(full) { +Data::Session &PhotoData::owner() const { + return *_owner; +} + +AuthSession &PhotoData::session() const { + return _owner->session(); } void PhotoData::automaticLoad( Data::FileOrigin origin, const HistoryItem *item) { - full->automaticLoad(origin, item); + _large->automaticLoad(origin, item); } void PhotoData::automaticLoadSettingsChanged() { - full->automaticLoadSettingsChanged(); + _large->automaticLoadSettingsChanged(); } void PhotoData::download(Data::FileOrigin origin) { - full->loadEvenCancelled(origin); - Auth().data().notifyPhotoLayoutChanged(this); + _large->loadEvenCancelled(origin); + _owner->notifyPhotoLayoutChanged(this); } bool PhotoData::loaded() const { bool wasLoading = loading(); - if (full->loaded()) { + if (_large->loaded()) { if (wasLoading) { - Auth().data().notifyPhotoLayoutChanged(this); + _owner->notifyPhotoLayoutChanged(this); } return true; } @@ -62,18 +54,18 @@ } bool PhotoData::loading() const { - return full->loading(); + return _large->loading(); } bool PhotoData::displayLoading() const { - return full->loading() - ? full->displayLoading() + return _large->loading() + ? _large->displayLoading() : (uploading() && !waitingForAlbum()); } void PhotoData::cancel() { - full->cancel(); - Auth().data().notifyPhotoLayoutChanged(this); + _large->cancel(); + _owner->notifyPhotoLayoutChanged(this); } float64 PhotoData::progress() const { @@ -83,7 +75,7 @@ } return 0; } - return full->progress(); + return _large->progress(); } void PhotoData::setWaitingForAlbum() { @@ -97,7 +89,7 @@ } int32 PhotoData::loadOffset() const { - return full->loadOffset(); + return _large->loadOffset(); } bool PhotoData::uploading() const { @@ -105,43 +97,42 @@ } void PhotoData::unload() { - // Forget thumb only when image cache limit exceeds. - //thumb->unload(); - medium->unload(); - full->unload(); - _replyPreview = nullptr; + // Forget thumbnail only when image cache limit exceeds. + //_thumbnailInline->unload(); + _thumbnailSmall->unload(); + _thumbnail->unload(); + _large->unload(); + _replyPreview.clear(); } Image *PhotoData::getReplyPreview(Data::FileOrigin origin) { - if (!_replyPreview && !thumb->isNull()) { - const auto previewFromImage = [&](const ImagePtr &image) { - if (!image->loaded()) { - image->load(origin); - return std::unique_ptr(); - } - int w = image->width(), h = image->height(); - if (w <= 0) w = 1; - if (h <= 0) h = 1; - return std::make_unique( - std::make_unique( - (w > h - ? image->pix( - origin, - w * st::msgReplyBarSize.height() / h, - st::msgReplyBarSize.height()) - : image->pix(origin, st::msgReplyBarSize.height()) - ).toImage(), - "PNG")); - }; - if (thumb->isDelayedStorageImage() - && !full->isNull() - && !full->isDelayedStorageImage()) { - _replyPreview = previewFromImage(full); - } else { - _replyPreview = previewFromImage(thumb); + if (_replyPreview + && (_replyPreview.good() || !_thumbnailSmall->loaded())) { + return _replyPreview.image(); + } + if (_thumbnailSmall->isDelayedStorageImage() + && !_large->isNull() + && !_large->isDelayedStorageImage() + && _large->loaded()) { + _replyPreview.prepare( + _large.get(), + origin, + Images::Option(0)); + } else if (_thumbnailSmall->loaded()) { + _replyPreview.prepare( + _thumbnailSmall.get(), + origin, + Images::Option(0)); + } else { + _thumbnailSmall->load(origin); + if (_thumbnailInline) { + _replyPreview.prepare( + _thumbnailInline.get(), + origin, + Images::Option::Blurred); } } - return _replyPreview.get(); + return _replyPreview.image(); } MTPInputPhoto PhotoData::mtpInput() const { @@ -151,23 +142,92 @@ MTP_bytes(fileReference)); } -void PhotoData::collectLocalData(PhotoData *local) { - if (local == this) return; +void PhotoData::collectLocalData(not_null local) { + if (local == this) { + return; + } - const auto copyImage = [](const ImagePtr &src, const ImagePtr &dst) { + const auto copyImage = [&](const ImagePtr &src, const ImagePtr &dst) { if (const auto from = src->cacheKey()) { if (const auto to = dst->cacheKey()) { - Auth().data().cache().copyIfEmpty(*from, *to); + _owner->cache().copyIfEmpty(*from, *to); + } + } + }; + copyImage(local->_thumbnailSmall, _thumbnailSmall); + copyImage(local->_thumbnail, _thumbnail); + copyImage(local->_large, _large); +} + +bool PhotoData::isNull() const { + return _large->isNull(); +} + +void PhotoData::loadThumbnail(Data::FileOrigin origin) { + _thumbnail->load(origin); +} + +void PhotoData::loadThumbnailSmall(Data::FileOrigin origin) { + _thumbnailSmall->load(origin); +} + +Image *PhotoData::thumbnailInline() const { + return _thumbnailInline ? _thumbnailInline.get() : nullptr; +} + +not_null PhotoData::thumbnailSmall() const { + return _thumbnailSmall.get(); +} + +not_null PhotoData::thumbnail() const { + return _thumbnail.get(); +} + +void PhotoData::load(Data::FileOrigin origin) { + _large->load(origin); +} + +not_null PhotoData::large() const { + return _large.get(); +} + +void PhotoData::updateImages( + ImagePtr thumbnailInline, + ImagePtr thumbnailSmall, + ImagePtr thumbnail, + ImagePtr large) { + if (!thumbnailSmall || !thumbnail || !large) { + return; + } + if (thumbnailInline && !_thumbnailInline) { + _thumbnailInline = thumbnailInline; + } + const auto update = [](ImagePtr &was, ImagePtr now) { + if (!was) { + was = now; + } else if (was->isDelayedStorageImage()) { + if (const auto location = now->location(); !location.isNull()) { + was->setDelayedStorageLocation( + Data::FileOrigin(), + location); } } }; - copyImage(local->thumb, thumb); - copyImage(local->medium, medium); - copyImage(local->full, full); + update(_thumbnailSmall, thumbnailSmall); + update(_thumbnail, thumbnail); + update(_large, large); +} + +int PhotoData::width() const { + return _large->width(); +} + +int PhotoData::height() const { + return _large->height(); } void PhotoOpenClickHandler::onClickImpl() const { - Messenger::Instance().showPhoto(this); + Core::App().showPhoto(this); } void PhotoSaveClickHandler::onClickImpl() const { diff -Nru telegram-desktop-1.5.8/Telegram/SourceFiles/data/data_photo.h telegram-desktop-1.5.11/Telegram/SourceFiles/data/data_photo.h --- telegram-desktop-1.5.8/Telegram/SourceFiles/data/data_photo.h 2019-01-21 17:28:45.000000000 +0000 +++ telegram-desktop-1.5.11/Telegram/SourceFiles/data/data_photo.h 2019-02-01 12:51:46.000000000 +0000 @@ -9,17 +9,18 @@ #include "data/data_types.h" +class AuthSession; + +namespace Data { +class Session; +} // namespace Data + class PhotoData { public: - explicit PhotoData(const PhotoId &id); - PhotoData( - const PhotoId &id, - const uint64 &access, - const QByteArray &fileReference, - TimeId date, - const ImagePtr &thumb, - const ImagePtr &medium, - const ImagePtr &full); + PhotoData(not_null owner, PhotoId id); + + [[nodiscard]] Data::Session &owner() const; + [[nodiscard]] AuthSession &session() const; void automaticLoad( Data::FileOrigin origin, @@ -27,35 +28,53 @@ void automaticLoadSettingsChanged(); void download(Data::FileOrigin origin); - bool loaded() const; - bool loading() const; - bool displayLoading() const; + [[nodiscard]] bool loaded() const; + [[nodiscard]] bool loading() const; + [[nodiscard]] bool displayLoading() const; void cancel(); - float64 progress() const; - int32 loadOffset() const; - bool uploading() const; + [[nodiscard]] float64 progress() const; + [[nodiscard]] int32 loadOffset() const; + [[nodiscard]] bool uploading() const; void setWaitingForAlbum(); - bool waitingForAlbum() const; + [[nodiscard]] bool waitingForAlbum() const; void unload(); - Image *getReplyPreview(Data::FileOrigin origin); + [[nodiscard]] Image *getReplyPreview(Data::FileOrigin origin); - MTPInputPhoto mtpInput() const; + [[nodiscard]] MTPInputPhoto mtpInput() const; // When we have some client-side generated photo // (for example for displaying an external inline bot result) // and it has downloaded full image, we can collect image from it // to (this) received from the server "same" photo. - void collectLocalData(PhotoData *local); + void collectLocalData(not_null local); + + bool isNull() const; + + void loadThumbnail(Data::FileOrigin origin); + void loadThumbnailSmall(Data::FileOrigin origin); + Image *thumbnailInline() const; + not_null thumbnailSmall() const; + not_null thumbnail() const; + + void load(Data::FileOrigin origin); + not_null large() const; + + // For now they return size of the 'large' image. + int width() const; + int height() const; + + void updateImages( + ImagePtr thumbnailInline, + ImagePtr thumbnailSmall, + ImagePtr thumbnail, + ImagePtr large); PhotoId id = 0; uint64 access = 0; QByteArray fileReference; TimeId date = 0; - ImagePtr thumb; - ImagePtr medium; - ImagePtr full; PeerData *peer = nullptr; // for chat and channel photos connection // geo, caption @@ -63,7 +82,14 @@ std::unique_ptr uploadingData; private: - std::unique_ptr _replyPreview; + ImagePtr _thumbnailInline; + ImagePtr _thumbnailSmall; + ImagePtr _thumbnail; + ImagePtr _large; + + Data::ReplyPreview _replyPreview; + + not_null _owner; }; diff -Nru telegram-desktop-1.5.8/Telegram/SourceFiles/data/data_search_controller.cpp telegram-desktop-1.5.11/Telegram/SourceFiles/data/data_search_controller.cpp --- telegram-desktop-1.5.8/Telegram/SourceFiles/data/data_search_controller.cpp 2019-01-21 17:28:45.000000000 +0000 +++ telegram-desktop-1.5.11/Telegram/SourceFiles/data/data_search_controller.cpp 2019-02-01 12:51:46.000000000 +0000 @@ -107,16 +107,16 @@ switch (data.type()) { case mtpc_messages_messages: { auto &d = data.c_messages_messages(); - App::feedUsers(d.vusers); - App::feedChats(d.vchats); + peer->owner().processUsers(d.vusers); + peer->owner().processChats(d.vchats); result.fullCount = d.vmessages.v.size(); return &d.vmessages.v; } break; case mtpc_messages_messagesSlice: { auto &d = data.c_messages_messagesSlice(); - App::feedUsers(d.vusers); - App::feedChats(d.vchats); + peer->owner().processUsers(d.vusers); + peer->owner().processChats(d.vchats); result.fullCount = d.vcount.v; return &d.vmessages.v; } break; @@ -129,8 +129,8 @@ LOG(("API Error: received messages.channelMessages when " "no channel was passed! (ParseSearchResult)")); } - App::feedUsers(d.vusers); - App::feedChats(d.vchats); + peer->owner().processUsers(d.vusers); + peer->owner().processChats(d.vchats); result.fullCount = d.vcount.v; return &d.vmessages.v; } break; @@ -151,7 +151,7 @@ auto addType = NewMessageExisting; result.messageIds.reserve(messages->size()); for (const auto &message : *messages) { - if (auto item = Auth().data().addNewMessage(message, addType)) { + if (auto item = peer->owner().addNewMessage(message, addType)) { auto itemId = item->id; if ((type == Storage::SharedMediaType::kCount) || item->sharedMediaTypes().test(type)) { @@ -178,9 +178,9 @@ } SearchController::CacheEntry::CacheEntry(const Query &query) -: peerData(App::peer(query.peerId)) +: peerData(Auth().data().peer(query.peerId)) , migratedData(query.migratedPeerId - ? base::make_optional(Data(App::peer(query.migratedPeerId))) + ? base::make_optional(Data(Auth().data().peer(query.migratedPeerId))) : std::nullopt) { } diff -Nru telegram-desktop-1.5.8/Telegram/SourceFiles/data/data_session.cpp telegram-desktop-1.5.11/Telegram/SourceFiles/data/data_session.cpp --- telegram-desktop-1.5.8/Telegram/SourceFiles/data/data_session.cpp 2019-01-21 17:28:45.000000000 +0000 +++ telegram-desktop-1.5.11/Telegram/SourceFiles/data/data_session.cpp 2019-02-01 12:51:46.000000000 +0000 @@ -10,7 +10,7 @@ #include "observer_peer.h" #include "auth_session.h" #include "apiwrap.h" -#include "messenger.h" +#include "core/application.h" #include "core/crash_reports.h" // for CrashReports::SetAnnotation #include "ui/image/image.h" #include "export/export_controller.h" @@ -57,23 +57,10 @@ // b: crop 320x320 // c: crop 640x640 // d: crop 1280x1280 -const auto ThumbLevels = QByteArray::fromRawData("isambcxydw", 10); -const auto MediumLevels = QByteArray::fromRawData("mbcxasydwi", 10); -const auto FullLevels = QByteArray::fromRawData("yxwmsdcbai", 10); - -void UpdateImage(ImagePtr &old, ImagePtr now) { - if (now->isNull()) { - return; - } - if (old->isNull()) { - old = now; - } else if (old->isDelayedStorageImage()) { - const auto location = now->location(); - if (!location.isNull()) { - old->setDelayedStorageLocation(Data::FileOrigin(), location); - } - } -} +const auto InlineLevels = QByteArray::fromRawData("i", 1); +const auto SmallLevels = QByteArray::fromRawData("sambcxydwi", 10); +const auto ThumbnailLevels = QByteArray::fromRawData("mbcxasydwi", 10); +const auto LargeLevels = QByteArray::fromRawData("yxwmsdcbai", 10); void CheckForSwitchInlineButton(not_null item) { if (item->out() || !item->hasSwitchInlineButton()) { @@ -121,22 +108,31 @@ return QString(); } -MTPPhotoSize FindDocumentThumb(const MTPDdocument &data) { +MTPPhotoSize FindDocumentInlineThumbnail(const MTPDdocument &data) { + const auto &thumbs = data.vthumbs.v; + const auto i = ranges::find( + thumbs, + mtpc_photoStrippedSize, + &MTPPhotoSize::type); + return (i != thumbs.end()) + ? (*i) + : MTPPhotoSize(MTP_photoSizeEmpty(MTP_string(""))); +} + +MTPPhotoSize FindDocumentThumbnail(const MTPDdocument &data) { const auto area = [](const MTPPhotoSize &size) { - static constexpr auto kInvalid = std::numeric_limits::max(); + static constexpr auto kInvalid = 0; return size.match([](const MTPDphotoSizeEmpty &) { return kInvalid; }, [](const MTPDphotoStrippedSize &) { return kInvalid; }, [](const auto &data) { - return (data.vw.v >= 90 || data.vh.v >= 90) - ? (data.vw.v * data.vh.v) - : kInvalid; + return (data.vw.v * data.vh.v); }); }; const auto &thumbs = data.vthumbs.v; - const auto i = ranges::max_element(thumbs, std::greater<>(), area); - return (i != thumbs.end()) + const auto i = ranges::max_element(thumbs, std::less<>(), area); + return (i != thumbs.end() && area(*i) > 0) ? (*i) : MTPPhotoSize(MTP_photoSizeEmpty(MTP_string(""))); } @@ -145,7 +141,7 @@ Session::Session(not_null session) : _session(session) -, _cache(Messenger::Instance().databases().get( +, _cache(Core::App().databases().get( Local::cachePath(), Local::cacheSettings())) , _selfDestructTimer([=] { checkSelfDestructItems(); }) @@ -233,7 +229,7 @@ return nullptr; } -not_null Session::user(const MTPUser &data) { +not_null Session::processUser(const MTPUser &data) { const auto result = user(data.match([](const auto &data) { return data.vid.v; })); @@ -409,7 +405,7 @@ return result; } -not_null Session::chat(const MTPChat &data) { +not_null Session::processChat(const MTPChat &data) { const auto result = data.match([&](const MTPDchat &data) { return peer(peerFromChat(data.vid.v)); }, [&](const MTPDchatForbidden &data) { @@ -621,7 +617,7 @@ UserData *Session::processUsers(const MTPVector &data) { auto result = (UserData*)nullptr; for (const auto &user : data.v) { - result = this->user(user); + result = processUser(user); } return result; } @@ -629,7 +625,7 @@ PeerData *Session::processChats(const MTPVector &data) { auto result = (PeerData*)nullptr; for (const auto &chat : data.v) { - result = this->chat(chat); + result = processChat(chat); } return result; } @@ -1609,75 +1605,68 @@ not_null Session::photo(PhotoId id) { auto i = _photos.find(id); if (i == _photos.end()) { - i = _photos.emplace(id, std::make_unique(id)).first; + i = _photos.emplace( + id, + std::make_unique(this, id)).first; } return i->second.get(); } -not_null Session::photo(const MTPPhoto &data) { - switch (data.type()) { - case mtpc_photo: - return photo(data.c_photo()); - - case mtpc_photoEmpty: - return photo(data.c_photoEmpty().vid.v); - } - Unexpected("Type in Session::photo()."); +not_null Session::processPhoto(const MTPPhoto &data) { + return data.match([&](const MTPDphoto &data) { + return processPhoto(data); + }, [&](const MTPDphotoEmpty &data) { + return photo(data.vid.v); + }); } -not_null Session::photo(const MTPDphoto &data) { +not_null Session::processPhoto(const MTPDphoto &data) { const auto result = photo(data.vid.v); photoApplyFields(result, data); return result; } -not_null Session::photo( +not_null Session::processPhoto( const MTPPhoto &data, const PreparedPhotoThumbs &thumbs) { - auto thumb = (const QImage*)nullptr; - auto medium = (const QImage*)nullptr; - auto full = (const QImage*)nullptr; - auto thumbLevel = -1; - auto mediumLevel = -1; - auto fullLevel = -1; - for (auto i = thumbs.cbegin(), e = thumbs.cend(); i != e; ++i) { - const auto newThumbLevel = ThumbLevels.indexOf(i.key()); - const auto newMediumLevel = MediumLevels.indexOf(i.key()); - const auto newFullLevel = FullLevels.indexOf(i.key()); - if (newThumbLevel < 0 || newMediumLevel < 0 || newFullLevel < 0) { - continue; - } - if (thumbLevel < 0 || newThumbLevel < thumbLevel) { - thumbLevel = newThumbLevel; - thumb = &i.value(); - } - if (mediumLevel < 0 || newMediumLevel < mediumLevel) { - mediumLevel = newMediumLevel; - medium = &i.value(); - } - if (fullLevel < 0 || newFullLevel < fullLevel) { - fullLevel = newFullLevel; - full = &i.value(); - } - } - if (!thumb || !medium || !full) { - return photo(0); - } - switch (data.type()) { - case mtpc_photo: - return photo( - data.c_photo().vid.v, - data.c_photo().vaccess_hash.v, - data.c_photo().vfile_reference.v, - data.c_photo().vdate.v, - Images::Create(base::duplicate(*thumb), "JPG"), - Images::Create(base::duplicate(*medium), "JPG"), - Images::Create(base::duplicate(*full), "JPG")); + Expects(!thumbs.empty()); - case mtpc_photoEmpty: - return photo(data.c_photoEmpty().vid.v); - } - Unexpected("Type in Session::photo() with prepared thumbs."); + const auto find = [&](const QByteArray &levels) { + const auto kInvalidIndex = int(levels.size()); + const auto level = [&](const auto &pair) { + const auto letter = pair.first; + const auto index = levels.indexOf(letter); + return (index >= 0) ? index : kInvalidIndex; + }; + const auto result = ranges::max_element( + thumbs, + std::greater<>(), + level); + return (level(*result) == kInvalidIndex) ? thumbs.end() : result; + }; + const auto image = [&](const QByteArray &levels) { + const auto i = find(levels); + return (i == thumbs.end()) + ? ImagePtr() + : Images::Create(base::duplicate(i->second), "JPG"); + }; + const auto thumbnailInline = image(InlineLevels); + const auto thumbnailSmall = image(SmallLevels); + const auto thumbnail = image(ThumbnailLevels); + const auto large = image(LargeLevels); + return data.match([&](const MTPDphoto &data) { + return photo( + data.vid.v, + data.vaccess_hash.v, + data.vfile_reference.v, + data.vdate.v, + thumbnailInline, + thumbnailSmall, + thumbnail, + large); + }, [&](const MTPDphotoEmpty &data) { + return photo(data.vid.v); + }); } not_null Session::photo( @@ -1685,31 +1674,29 @@ const uint64 &access, const QByteArray &fileReference, TimeId date, - const ImagePtr &thumb, - const ImagePtr &medium, - const ImagePtr &full) { + const ImagePtr &thumbnailInline, + const ImagePtr &thumbnailSmall, + const ImagePtr &thumbnail, + const ImagePtr &large) { const auto result = photo(id); photoApplyFields( result, access, fileReference, date, - thumb, - medium, - full); + thumbnailInline, + thumbnailSmall, + thumbnail, + large); return result; } void Session::photoConvert( not_null original, const MTPPhoto &data) { - const auto id = [&] { - switch (data.type()) { - case mtpc_photo: return data.c_photo().vid.v; - case mtpc_photoEmpty: return data.c_photoEmpty().vid.v; - } - Unexpected("Type in Session::photoConvert()."); - }(); + const auto id = data.match([](const auto &data) { + return data.vid.v; + }); if (original->id != id) { auto i = _photos.find(id); if (i == _photos.end()) { @@ -1732,23 +1719,26 @@ PhotoData *Session::photoFromWeb( const MTPWebDocument &data, - ImagePtr thumb, + ImagePtr thumbnailSmall, bool willBecomeNormal) { - const auto full = Images::Create(data); - if (full->isNull()) { + const auto large = Images::Create(data); + const auto thumbnailInline = ImagePtr(); + if (large->isNull()) { return nullptr; } - auto medium = ImagePtr(); + auto thumbnail = large; if (willBecomeNormal) { - const auto width = full->width(); - const auto height = full->height(); - if (thumb->isNull()) { + const auto width = large->width(); + const auto height = large->height(); + if (thumbnailSmall->isNull()) { auto thumbsize = shrinkToKeepAspect(width, height, 100, 100); - thumb = Images::Create(thumbsize.width(), thumbsize.height()); + thumbnailSmall = Images::Create(thumbsize.width(), thumbsize.height()); } auto mediumsize = shrinkToKeepAspect(width, height, 320, 320); - medium = Images::Create(mediumsize.width(), mediumsize.height()); + thumbnail = Images::Create(mediumsize.width(), mediumsize.height()); + } else if (thumbnailSmall->isNull()) { + thumbnailSmall = large; } return photo( @@ -1756,9 +1746,10 @@ uint64(0), QByteArray(), unixtime(), - thumb, - medium, - full); + thumbnailInline, + thumbnailSmall, + thumbnail, + large); } void Session::photoApplyFields( @@ -1772,48 +1763,42 @@ void Session::photoApplyFields( not_null photo, const MTPDphoto &data) { - auto thumb = (const MTPPhotoSize*)nullptr; - auto medium = (const MTPPhotoSize*)nullptr; - auto full = (const MTPPhotoSize*)nullptr; - auto thumbLevel = -1; - auto mediumLevel = -1; - auto fullLevel = -1; - for (const auto &sizeData : data.vsizes.v) { - const auto sizeLetter = sizeData.match([](MTPDphotoSizeEmpty) { - return char(0); - }, [](const auto &size) { - return size.vtype.v.isEmpty() ? char(0) : size.vtype.v[0]; - }); - if (!sizeLetter) continue; - - const auto newThumbLevel = ThumbLevels.indexOf(sizeLetter); - const auto newMediumLevel = MediumLevels.indexOf(sizeLetter); - const auto newFullLevel = FullLevels.indexOf(sizeLetter); - if (newThumbLevel < 0 || newMediumLevel < 0 || newFullLevel < 0) { - continue; - } - if (thumbLevel < 0 || newThumbLevel < thumbLevel) { - thumbLevel = newThumbLevel; - thumb = &sizeData; - } - if (mediumLevel < 0 || newMediumLevel < mediumLevel) { - mediumLevel = newMediumLevel; - medium = &sizeData; - } - if (fullLevel < 0 || newFullLevel < fullLevel) { - fullLevel = newFullLevel; - full = &sizeData; - } - } - if (thumb && medium && full) { + const auto &sizes = data.vsizes.v; + const auto find = [&](const QByteArray &levels) { + const auto kInvalidIndex = int(levels.size()); + const auto level = [&](const MTPPhotoSize &size) { + const auto letter = size.match([](const MTPDphotoSizeEmpty &) { + return char(0); + }, [](const auto &size) { + return size.vtype.v.isEmpty() ? char(0) : size.vtype.v[0]; + }); + const auto index = levels.indexOf(letter); + return (index >= 0) ? index : kInvalidIndex; + }; + const auto result = ranges::max_element( + sizes, + std::greater<>(), + level); + return (level(*result) == kInvalidIndex) ? sizes.end() : result; + }; + const auto image = [&](const QByteArray &levels) { + const auto i = find(levels); + return (i == sizes.end()) ? ImagePtr() : App::image(*i); + }; + const auto thumbnailInline = image(InlineLevels); + const auto thumbnailSmall = image(SmallLevels); + const auto thumbnail = image(ThumbnailLevels); + const auto large = image(LargeLevels); + if (thumbnailSmall && thumbnail && large) { photoApplyFields( photo, data.vaccess_hash.v, data.vfile_reference.v, data.vdate.v, - App::image(*thumb), - App::image(*medium), - App::image(*full)); + thumbnailInline, + thumbnailSmall, + thumbnail, + large); } } @@ -1822,18 +1807,21 @@ const uint64 &access, const QByteArray &fileReference, TimeId date, - const ImagePtr &thumb, - const ImagePtr &medium, - const ImagePtr &full) { + const ImagePtr &thumbnailInline, + const ImagePtr &thumbnailSmall, + const ImagePtr &thumbnail, + const ImagePtr &large) { if (!date) { return; } photo->access = access; photo->fileReference = fileReference; photo->date = date; - UpdateImage(photo->thumb, thumb); - UpdateImage(photo->medium, medium); - UpdateImage(photo->full, full); + photo->updateImages( + thumbnailInline, + thumbnailSmall, + thumbnail, + large); } not_null Session::document(DocumentId id) { @@ -1841,15 +1829,15 @@ if (i == _documents.cend()) { i = _documents.emplace( id, - std::make_unique(id, _session)).first; + std::make_unique(this, id)).first; } return i->second.get(); } -not_null Session::document(const MTPDocument &data) { +not_null Session::processDocument(const MTPDocument &data) { switch (data.type()) { case mtpc_document: - return document(data.c_document()); + return processDocument(data.c_document()); case mtpc_documentEmpty: return document(data.c_documentEmpty().vid.v); @@ -1857,13 +1845,13 @@ Unexpected("Type in Session::document()."); } -not_null Session::document(const MTPDdocument &data) { +not_null Session::processDocument(const MTPDdocument &data) { const auto result = document(data.vid.v); documentApplyFields(result, data); return result; } -not_null Session::document( +not_null Session::processDocument( const MTPdocument &data, QImage &&thumb) { switch (data.type()) { @@ -1879,6 +1867,7 @@ fields.vdate.v, fields.vattributes.v, qs(fields.vmime_type), + ImagePtr(), Images::Create(std::move(thumb), "JPG"), fields.vdc_id.v, fields.vsize.v, @@ -1895,7 +1884,8 @@ TimeId date, const QVector &attributes, const QString &mime, - const ImagePtr &thumb, + const ImagePtr &thumbnailInline, + const ImagePtr &thumbnail, int32 dc, int32 size, const StorageImageLocation &thumbLocation) { @@ -1907,7 +1897,8 @@ date, attributes, mime, - thumb, + thumbnailInline, + thumbnail, dc, size, thumbLocation); @@ -1979,6 +1970,7 @@ unixtime(), data.vattributes.v, data.vmime_type.v, + ImagePtr(), thumb, MTP::maindc(), int32(0), // data.vsize.v @@ -2000,6 +1992,7 @@ unixtime(), data.vattributes.v, data.vmime_type.v, + ImagePtr(), thumb, MTP::maindc(), int32(0), // data.vsize.v @@ -2019,7 +2012,8 @@ void Session::documentApplyFields( not_null document, const MTPDdocument &data) { - const auto thumb = FindDocumentThumb(data); + const auto thumbnailInline = FindDocumentInlineThumbnail(data); + const auto thumbnail = FindDocumentThumbnail(data); documentApplyFields( document, data.vaccess_hash.v, @@ -2027,10 +2021,11 @@ data.vdate.v, data.vattributes.v, qs(data.vmime_type), - App::image(thumb), + App::image(thumbnailInline), + App::image(thumbnail), data.vdc_id.v, data.vsize.v, - StorageImageLocation::FromMTP(thumb)); + StorageImageLocation::FromMTP(thumbnail)); } void Session::documentApplyFields( @@ -2040,7 +2035,8 @@ TimeId date, const QVector &attributes, const QString &mime, - const ImagePtr &thumb, + const ImagePtr &thumbnailInline, + const ImagePtr &thumbnail, int32 dc, int32 size, const StorageImageLocation &thumbLocation) { @@ -2053,13 +2049,7 @@ } document->date = date; document->setMimeString(mime); - if (!thumb->isNull() - && (document->thumb->isNull() - || (document->sticker() - && (document->thumb->width() < thumb->width() - || document->thumb->height() < thumb->height())))) { - document->thumb = thumb; - } + document->updateThumbnails(thumbnailInline, thumbnail); document->size = size; document->recountIsImage(); if (document->sticker() @@ -2077,10 +2067,10 @@ return i->second.get(); } -not_null Session::webpage(const MTPWebPage &data) { +not_null Session::processWebpage(const MTPWebPage &data) { switch (data.type()) { case mtpc_webPage: - return webpage(data.c_webPage()); + return processWebpage(data.c_webPage()); case mtpc_webPageEmpty: { const auto result = webpage(data.c_webPageEmpty().vid.v); if (result->pendingTill > 0) { @@ -2089,7 +2079,7 @@ return result; } break; case mtpc_webPagePending: - return webpage(data.c_webPagePending()); + return processWebpage(data.c_webPagePending()); case mtpc_webPageNotModified: LOG(("API Error: " "webPageNotModified is unexpected in Session::webpage().")); @@ -2098,13 +2088,13 @@ Unexpected("Type in Session::webpage()."); } -not_null Session::webpage(const MTPDwebPage &data) { +not_null Session::processWebpage(const MTPDwebPage &data) { const auto result = webpage(data.vid.v); webpageApplyFields(result, data); return result; } -not_null Session::webpage(const MTPDwebPagePending &data) { +not_null Session::processWebpage(const MTPDwebPagePending &data) { constexpr auto kDefaultPendingTimeout = 60; const auto result = webpage(data.vid.v); webpageApplyFields( @@ -2203,8 +2193,10 @@ siteName, data.has_title() ? qs(data.vtitle) : QString(), description, - data.has_photo() ? photo(data.vphoto).get() : nullptr, - data.has_document() ? document(data.vdocument).get() : nullptr, + data.has_photo() ? processPhoto(data.vphoto).get() : nullptr, + (data.has_document() + ? processDocument(data.vdocument).get() + : nullptr), WebPageCollage(data), data.has_duration() ? data.vduration.v : 0, data.has_author() ? qs(data.vauthor) : QString(), @@ -2255,7 +2247,7 @@ return i->second.get(); } -not_null Session::game(const MTPDgame &data) { +not_null Session::processGame(const MTPDgame &data) { const auto result = game(data.vid.v); gameApplyFields(result, data); return result; @@ -2316,8 +2308,10 @@ qs(data.vshort_name), qs(data.vtitle), qs(data.vdescription), - photo(data.vphoto), - data.has_document() ? document(data.vdocument).get() : nullptr); + processPhoto(data.vphoto), + (data.has_document() + ? processDocument(data.vdocument).get() + : nullptr)); } void Session::gameApplyFields( @@ -2348,7 +2342,7 @@ return i->second.get(); } -not_null Session::poll(const MTPPoll &data) { +not_null Session::processPoll(const MTPPoll &data) { return data.match([&](const MTPDpoll &data) { const auto id = data.vid.v; const auto result = poll(id); @@ -2360,8 +2354,8 @@ }); } -not_null Session::poll(const MTPDmessageMediaPoll &data) { - const auto result = poll(data.vpoll); +not_null Session::processPoll(const MTPDmessageMediaPoll &data) { + const auto result = processPoll(data.vpoll); const auto changed = result->applyResults(data.vresults); if (changed) { notifyPollUpdateDelayed(result); @@ -2375,7 +2369,7 @@ return (i == end(_polls)) ? nullptr : update.has_poll() - ? poll(update.vpoll).get() + ? processPoll(update.vpoll).get() : i->second.get(); }(); if (updated && updated->applyResults(update.vresults)) { @@ -2949,7 +2943,7 @@ const MTPMessageMedia &media) { const auto date = unixtime(); if (!userLoaded(ServiceUserId)) { - user(MTP_user( + processUser(MTP_user( MTP_flags( MTPDuser::Flag::f_first_name | MTPDuser::Flag::f_phone @@ -3076,38 +3070,23 @@ qsl(":/gui/art/bg.jpg"), "JPG"); if (defaultBackground) { - _wallpapers.push_back({ - Window::Theme::kDefaultBackground, - 0ULL, // access_hash - MTPDwallPaper::Flags(0), - QString(), // slug - defaultBackground - }); + _wallpapers.push_back(Data::DefaultWallPaper()); + _wallpapers.back().setLocalImageAsThumbnail( + defaultBackground.get()); } const auto oldBackground = Images::Create( qsl(":/gui/art/bg_initial.jpg"), "JPG"); if (oldBackground) { - _wallpapers.push_back({ - Window::Theme::kInitialBackground, - 0ULL, // access_hash - MTPDwallPaper::Flags(0), - QString(), // slug - oldBackground - }); + _wallpapers.push_back(Data::Legacy1DefaultWallPaper()); + _wallpapers.back().setLocalImageAsThumbnail(oldBackground.get()); } for (const auto &paper : data) { paper.match([&](const MTPDwallPaper &paper) { - const auto document = this->document(paper.vdocument); - if (document->checkWallPaperProperties()) { - _wallpapers.push_back({ - paper.vid.v, - paper.vaccess_hash.v, - paper.vflags.v, - qs(paper.vslug), - document->thumb, - document, - }); + if (paper.is_pattern()) { + return; + } else if (const auto parsed = Data::WallPaper::Create(paper)) { + _wallpapers.push_back(*parsed); } }); } diff -Nru telegram-desktop-1.5.8/Telegram/SourceFiles/data/data_session.h telegram-desktop-1.5.11/Telegram/SourceFiles/data/data_session.h --- telegram-desktop-1.5.8/Telegram/SourceFiles/data/data_session.h 2019-01-21 17:28:45.000000000 +0000 +++ telegram-desktop-1.5.11/Telegram/SourceFiles/data/data_session.h 2019-02-01 12:51:46.000000000 +0000 @@ -51,7 +51,7 @@ enum class FeedUpdateFlag; struct FeedUpdate; -struct WallPaper; +class WallPaper; class Session final { public: @@ -84,17 +84,25 @@ Storage::Cache::Database &cache(); [[nodiscard]] not_null peer(PeerId id); + [[nodiscard]] not_null peer(UserId id) = delete; [[nodiscard]] not_null user(UserId id); [[nodiscard]] not_null chat(ChatId id); [[nodiscard]] not_null channel(ChannelId id); + [[nodiscard]] not_null user(PeerId id) = delete; + [[nodiscard]] not_null chat(PeerId id) = delete; + [[nodiscard]] not_null channel(PeerId id) = delete; [[nodiscard]] PeerData *peerLoaded(PeerId id) const; + [[nodiscard]] PeerData *peerLoaded(UserId id) const = delete; [[nodiscard]] UserData *userLoaded(UserId id) const; [[nodiscard]] ChatData *chatLoaded(ChatId id) const; [[nodiscard]] ChannelData *channelLoaded(ChannelId id) const; + [[nodiscard]] UserData *userLoaded(PeerId id) const = delete; + [[nodiscard]] ChatData *chatLoaded(PeerId id) const = delete; + [[nodiscard]] ChannelData *channelLoaded(PeerId id) const = delete; - not_null user(const MTPUser &data); - not_null chat(const MTPChat &data); + not_null processUser(const MTPUser &data); + not_null processChat(const MTPChat &data); // Returns last user, if there were any. UserData *processUsers(const MTPVector &data); @@ -107,10 +115,12 @@ void enumerateChannels(Fn)> action) const; [[nodiscard]] PeerData *peerByUsername(const QString &username) const; - not_null history(PeerId peerId); - History *historyLoaded(PeerId peerId) const; - not_null history(not_null peer); - History *historyLoaded(const PeerData *peer); + [[nodiscard]] not_null history(PeerId peerId); + [[nodiscard]] History *historyLoaded(PeerId peerId) const; + [[nodiscard]] not_null history(UserId userId) = delete; + [[nodiscard]] History *historyLoaded(UserId userId) const = delete; + [[nodiscard]] not_null history(not_null peer); + [[nodiscard]] History *historyLoaded(const PeerData *peer); void registerSendAction( not_null history, @@ -307,8 +317,6 @@ -> rpl::producer; void updateSendActionAnimation(SendActionAnimationUpdate &&update); - void updateSendActionAnimation(); - int unreadBadge() const; bool unreadBadgeMuted() const; int unreadBadgeIgnoreOne(History *history) const; @@ -323,61 +331,63 @@ void selfDestructIn(not_null item, TimeMs delay); - not_null photo(PhotoId id); - not_null photo(const MTPPhoto &data); - not_null photo(const MTPDphoto &data); - not_null photo( + [[nodiscard]] not_null photo(PhotoId id); + not_null processPhoto(const MTPPhoto &data); + not_null processPhoto(const MTPDphoto &data); + not_null processPhoto( const MTPPhoto &data, const PreparedPhotoThumbs &thumbs); - not_null photo( + [[nodiscard]] not_null photo( PhotoId id, const uint64 &access, const QByteArray &fileReference, TimeId date, - const ImagePtr &thumb, - const ImagePtr &medium, - const ImagePtr &full); + const ImagePtr &thumbnailInline, + const ImagePtr &thumbnailSmall, + const ImagePtr &thumbnail, + const ImagePtr &large); void photoConvert( not_null original, const MTPPhoto &data); - PhotoData *photoFromWeb( + [[nodiscard]] PhotoData *photoFromWeb( const MTPWebDocument &data, - ImagePtr thumb = ImagePtr(), + ImagePtr thumbnailSmall = ImagePtr(), bool willBecomeNormal = false); - not_null document(DocumentId id); - not_null document(const MTPDocument &data); - not_null document(const MTPDdocument &data); - not_null document( + [[nodiscard]] not_null document(DocumentId id); + not_null processDocument(const MTPDocument &data); + not_null processDocument(const MTPDdocument &data); + not_null processDocument( const MTPdocument &data, QImage &&thumb); - not_null document( + [[nodiscard]] not_null document( DocumentId id, const uint64 &access, const QByteArray &fileReference, TimeId date, const QVector &attributes, const QString &mime, - const ImagePtr &thumb, + const ImagePtr &thumbnailInline, + const ImagePtr &thumbnail, int32 dc, int32 size, const StorageImageLocation &thumbLocation); void documentConvert( not_null original, const MTPDocument &data); - DocumentData *documentFromWeb( + [[nodiscard]] DocumentData *documentFromWeb( const MTPWebDocument &data, ImagePtr thumb); - not_null webpage(WebPageId id); - not_null webpage(const MTPWebPage &data); - not_null webpage(const MTPDwebPage &data); - not_null webpage(const MTPDwebPagePending &data); - not_null webpage( + [[nodiscard]] not_null webpage(WebPageId id); + not_null processWebpage(const MTPWebPage &data); + not_null processWebpage(const MTPDwebPage &data); + not_null processWebpage(const MTPDwebPagePending &data); + [[nodiscard]] not_null webpage( WebPageId id, const QString &siteName, const TextWithEntities &content); - not_null webpage( + [[nodiscard]] not_null webpage( WebPageId id, WebPageType type, const QString &url, @@ -392,9 +402,9 @@ const QString &author, TimeId pendingTill); - not_null game(GameId id); - not_null game(const MTPDgame &data); - not_null game( + [[nodiscard]] not_null game(GameId id); + not_null processGame(const MTPDgame &data); + [[nodiscard]] not_null game( GameId id, const uint64 &accessHash, const QString &shortName, @@ -406,11 +416,12 @@ not_null original, const MTPGame &data); - not_null poll(PollId id); - not_null poll(const MTPPoll &data); - not_null poll(const MTPDmessageMediaPoll &data); + [[nodiscard]] not_null poll(PollId id); + not_null processPoll(const MTPPoll &data); + not_null processPoll(const MTPDmessageMediaPoll &data); - not_null location(const LocationCoords &coords); + [[nodiscard]] not_null location( + const LocationCoords &coords); void registerPhotoItem( not_null photo, @@ -562,9 +573,10 @@ const uint64 &access, const QByteArray &fileReference, TimeId date, - const ImagePtr &thumb, - const ImagePtr &medium, - const ImagePtr &full); + const ImagePtr &thumbnailInline, + const ImagePtr &thumbnailSmall, + const ImagePtr &thumbnail, + const ImagePtr &large); void documentApplyFields( not_null document, @@ -579,7 +591,8 @@ TimeId date, const QVector &attributes, const QString &mime, - const ImagePtr &thumb, + const ImagePtr &thumbnailInline, + const ImagePtr &thumbnail, int32 dc, int32 size, const StorageImageLocation &thumbLocation); diff -Nru telegram-desktop-1.5.8/Telegram/SourceFiles/data/data_shared_media.cpp telegram-desktop-1.5.11/Telegram/SourceFiles/data/data_shared_media.cpp --- telegram-desktop-1.5.8/Telegram/SourceFiles/data/data_shared_media.cpp 2019-01-21 17:28:45.000000000 +0000 +++ telegram-desktop-1.5.11/Telegram/SourceFiles/data/data_shared_media.cpp 2019-02-01 12:51:46.000000000 +0000 @@ -76,7 +76,7 @@ limitBefore, limitAfter); auto requestMediaAround = [ - peer = App::peer(key.peerId), + peer = Auth().data().peer(key.peerId), type = key.type ](const SparseIdsSliceBuilder::AroundData &data) { Auth().api().requestSharedMedia( @@ -313,7 +313,7 @@ std::optional SharedMediaWithLastSlice::LastPeerPhotoId( PeerId peerId) { - if (auto peer = App::peerLoaded(peerId)) { + if (const auto peer = Auth().data().peerLoaded(peerId)) { return peer->userpicPhotoUnknown() ? std::nullopt : base::make_optional(peer->userpicPhotoId()); diff -Nru telegram-desktop-1.5.8/Telegram/SourceFiles/data/data_types.cpp telegram-desktop-1.5.11/Telegram/SourceFiles/data/data_types.cpp --- telegram-desktop-1.5.8/Telegram/SourceFiles/data/data_types.cpp 2019-01-21 17:28:45.000000000 +0000 +++ telegram-desktop-1.5.11/Telegram/SourceFiles/data/data_types.cpp 2019-02-01 12:51:46.000000000 +0000 @@ -8,6 +8,8 @@ #include "data/data_types.h" #include "data/data_document.h" +#include "data/data_file_origin.h" +#include "ui/image/image_source.h" #include "ui/widgets/input_fields.h" #include "storage/cache/storage_cache_types.h" #include "base/openssl_help.h" @@ -30,6 +32,20 @@ } // namespace +struct ReplyPreview::Data { + Data(std::unique_ptr &&source, bool good); + + Image image; + bool good = false; +}; + +ReplyPreview::Data::Data( + std::unique_ptr &&source, + bool good) +: image(std::move(source)) +, good(good) { +} + Storage::Cache::Key DocumentCacheKey(int32 dcId, uint64 id) { return Storage::Cache::Key{ Data::kDocumentCacheTag | (uint64(dcId) & Data::kDocumentCacheMask), @@ -98,6 +114,63 @@ }; } +ReplyPreview::ReplyPreview() = default; + +ReplyPreview::ReplyPreview(ReplyPreview &&other) = default; + +ReplyPreview &ReplyPreview::operator=(ReplyPreview &&other) = default; + +ReplyPreview::~ReplyPreview() = default; + +void ReplyPreview::prepare( + not_null image, + FileOrigin origin, + Images::Options options) { + int w = image->width(), h = image->height(); + if (w <= 0) w = 1; + if (h <= 0) h = 1; + auto thumbSize = (w > h) + ? QSize( + w * st::msgReplyBarSize.height() / h, + st::msgReplyBarSize.height()) + : QSize( + st::msgReplyBarSize.height(), + h * st::msgReplyBarSize.height() / w); + thumbSize *= cIntRetinaFactor(); + const auto prepareOptions = Images::Option::Smooth + | Images::Option::TransparentBackground + | options; + auto outerSize = st::msgReplyBarSize.height(); + auto bitmap = image->pixNoCache( + origin, + thumbSize.width(), + thumbSize.height(), + prepareOptions, + outerSize, + outerSize); + _data = std::make_unique( + std::make_unique( + bitmap.toImage(), + "PNG"), + ((options & Images::Option::Blurred) == 0)); +} + +void ReplyPreview::clear() { + _data = nullptr; +} + +Image *ReplyPreview::image() const { + return _data ? &_data->image : nullptr; +} + +bool ReplyPreview::good() const { + return !empty() && _data->good; +} + +bool ReplyPreview::empty() const { + return !_data; +} + } // namespace Data void AudioMsgId::setTypeFromAudio() { diff -Nru telegram-desktop-1.5.8/Telegram/SourceFiles/data/data_types.h telegram-desktop-1.5.11/Telegram/SourceFiles/data/data_types.h --- telegram-desktop-1.5.8/Telegram/SourceFiles/data/data_types.h 2019-01-21 17:28:45.000000000 +0000 +++ telegram-desktop-1.5.11/Telegram/SourceFiles/data/data_types.h 2019-02-01 12:51:46.000000000 +0000 @@ -23,6 +23,11 @@ class InputField; } // namespace Ui +namespace Images { +enum class Option; +using Options = base::flags