diff --git a/.gitignore b/.gitignore index 94b1d353e..a155d81c7 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ /Telegram/SourceFiles/art/sprite_125x.png /Telegram/SourceFiles/art/sprite_150x.png /Telegram/*.user +*.vcxproj.user *.suo *.sdf *.opensdf diff --git a/.travis.yml b/.travis.yml index 612e30f7a..11f305e48 100644 --- a/.travis.yml +++ b/.travis.yml @@ -39,5 +39,9 @@ arch: - libtool --finish /usr/lib - .travis/build.sh +before_install: + - "export TRAVIS_COMMIT_MSG=\"$(git log --format=%B --no-merges -n 1)\"" + - .travis/check.sh + script: - .travis/arch.sh \ No newline at end of file diff --git a/.travis/build.sh b/.travis/build.sh index ebbaeffc4..7deae1f95 100755 --- a/.travis/build.sh +++ b/.travis/build.sh @@ -10,23 +10,6 @@ run() { check } -# set colors -RCol='\e[0m' # Text Reset - -# Regular Bold Underline High Intensity BoldHigh Intens Background High Intensity Backgrounds -Bla='\e[0;30m'; BBla='\e[1;30m'; UBla='\e[4;30m'; IBla='\e[0;90m'; BIBla='\e[1;90m'; On_Bla='\e[40m'; On_IBla='\e[0;100m'; -Red='\e[0;31m'; BRed='\e[1;31m'; URed='\e[4;31m'; IRed='\e[0;91m'; BIRed='\e[1;91m'; On_Red='\e[41m'; On_IRed='\e[0;101m'; -Gre='\e[0;32m'; BGre='\e[1;32m'; UGre='\e[4;32m'; IGre='\e[0;92m'; BIGre='\e[1;92m'; On_Gre='\e[42m'; On_IGre='\e[0;102m'; -Yel='\e[0;33m'; BYel='\e[1;33m'; UYel='\e[4;33m'; IYel='\e[0;93m'; BIYel='\e[1;93m'; On_Yel='\e[43m'; On_IYel='\e[0;103m'; -Blu='\e[0;34m'; BBlu='\e[1;34m'; UBlu='\e[4;34m'; IBlu='\e[0;94m'; BIBlu='\e[1;94m'; On_Blu='\e[44m'; On_IBlu='\e[0;104m'; -Pur='\e[0;35m'; BPur='\e[1;35m'; UPur='\e[4;35m'; IPur='\e[0;95m'; BIPur='\e[1;95m'; On_Pur='\e[45m'; On_IPur='\e[0;105m'; -Cya='\e[0;36m'; BCya='\e[1;36m'; UCya='\e[4;36m'; ICya='\e[0;96m'; BICya='\e[1;96m'; On_Cya='\e[46m'; On_ICya='\e[0;106m'; -Whi='\e[0;37m'; BWhi='\e[1;37m'; UWhi='\e[4;37m'; IWhi='\e[0;97m'; BIWhi='\e[1;97m'; On_Whi='\e[47m'; On_IWhi='\e[0;107m'; - -# Set variables -_qtver=5.5.1 -srcdir=${PWD} - downloadLibs() { travis_fold_start "download_libs" # Move telegram project to subfolder @@ -172,28 +155,6 @@ check() { fi } -start_msg() { - echo -e "\n${Gre}$*${RCol}" -} - -info_msg() { - echo -e "\n${Cya}$*${RCol}" -} - -error_msg() { - echo -e "\n${BRed}$*${RCol}" -} - -success_msg() { - echo -e "\n${BGre}$*${RCol}" -} - -travis_fold_start() { - echo "travis_fold:start:$*" -} - -travis_fold_end() { - echo "travis_fold:end:$*" -} +source ./.travis/common.sh run diff --git a/.travis/check.sh b/.travis/check.sh new file mode 100755 index 000000000..3fe7c7fd3 --- /dev/null +++ b/.travis/check.sh @@ -0,0 +1,25 @@ +#!/bin/bash +# Checks commit message, ... + +run() { + checkCommitMessage +} + +checkCommitMessage() { + info_msg "Commit message: ${TRAVIS_COMMIT_MSG}"; + info_msg "Is pull request: ${TRAVIS_PULL_REQUEST}"; + + if [[ $TRAVIS_PULL_REQUEST != "false" ]];then + if [[ $TRAVIS_COMMIT_MSG != *"Signed-off-by: "* ]];then + error_msg "The commit message does not contain the signature!" + error_msg "More information: https://github.com/telegramdesktop/tdesktop/blob/master/.github/CONTRIBUTING.md#sign-your-work" + exit 1 + else + success_msg "Commit message contains signature" + fi + fi +} + +source ./.travis/common.sh + +run diff --git a/.travis/common.sh b/.travis/common.sh new file mode 100755 index 000000000..dd3bb1967 --- /dev/null +++ b/.travis/common.sh @@ -0,0 +1,40 @@ +# set colors +RCol='\e[0m' # Text Reset + +# Regular Bold Underline High Intensity BoldHigh Intens Background High Intensity Backgrounds +Bla='\e[0;30m'; BBla='\e[1;30m'; UBla='\e[4;30m'; IBla='\e[0;90m'; BIBla='\e[1;90m'; On_Bla='\e[40m'; On_IBla='\e[0;100m'; +Red='\e[0;31m'; BRed='\e[1;31m'; URed='\e[4;31m'; IRed='\e[0;91m'; BIRed='\e[1;91m'; On_Red='\e[41m'; On_IRed='\e[0;101m'; +Gre='\e[0;32m'; BGre='\e[1;32m'; UGre='\e[4;32m'; IGre='\e[0;92m'; BIGre='\e[1;92m'; On_Gre='\e[42m'; On_IGre='\e[0;102m'; +Yel='\e[0;33m'; BYel='\e[1;33m'; UYel='\e[4;33m'; IYel='\e[0;93m'; BIYel='\e[1;93m'; On_Yel='\e[43m'; On_IYel='\e[0;103m'; +Blu='\e[0;34m'; BBlu='\e[1;34m'; UBlu='\e[4;34m'; IBlu='\e[0;94m'; BIBlu='\e[1;94m'; On_Blu='\e[44m'; On_IBlu='\e[0;104m'; +Pur='\e[0;35m'; BPur='\e[1;35m'; UPur='\e[4;35m'; IPur='\e[0;95m'; BIPur='\e[1;95m'; On_Pur='\e[45m'; On_IPur='\e[0;105m'; +Cya='\e[0;36m'; BCya='\e[1;36m'; UCya='\e[4;36m'; ICya='\e[0;96m'; BICya='\e[1;96m'; On_Cya='\e[46m'; On_ICya='\e[0;106m'; +Whi='\e[0;37m'; BWhi='\e[1;37m'; UWhi='\e[4;37m'; IWhi='\e[0;97m'; BIWhi='\e[1;97m'; On_Whi='\e[47m'; On_IWhi='\e[0;107m'; + +# Set variables +_qtver=5.5.1 +srcdir=${PWD} + +start_msg() { + echo -e "\n${Gre}$*${RCol}" +} + +info_msg() { + echo -e "\n${Cya}$*${RCol}" +} + +error_msg() { + echo -e "\n${BRed}$*${RCol}" +} + +success_msg() { + echo -e "\n${BGre}$*${RCol}" +} + +travis_fold_start() { + echo "travis_fold:start:$*" +} + +travis_fold_end() { + echo "travis_fold:end:$*" +} diff --git a/Telegram.sln b/Telegram.sln index 836d4a043..6487c468a 100644 --- a/Telegram.sln +++ b/Telegram.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2013 -VisualStudioVersion = 12.0.30501.0 +# Visual Studio 14 +VisualStudioVersion = 14.0.24720.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Telegram", "Telegram\Telegram.vcxproj", "{B12702AD-ABFB-343A-A199-8E24837244A3}" ProjectSection(ProjectDependencies) = postProject @@ -18,10 +18,12 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Updater", "Telegram\Updater EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MetaLang", "Telegram\MetaLang.vcxproj", "{E417CAA4-259B-4C99-88E3-805F1300E8EB}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{2F863EAD-33C9-4014-A573-93F085BA9CB1}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "codegen", "codegen", "{2F863EAD-33C9-4014-A573-93F085BA9CB1}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Packer", "Telegram\Packer.vcxproj", "{56A9A4B2-21E5-4360-AFA8-85B43AC43B08}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "codegen_style", "Telegram\build\vc\codegen_style\codegen_style.vcxproj", "{E4DF8176-4DEF-4859-962F-B497E3E7A323}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 @@ -82,8 +84,21 @@ Global {56A9A4B2-21E5-4360-AFA8-85B43AC43B08}.Deploy|x64.ActiveCfg = Release|Win32 {56A9A4B2-21E5-4360-AFA8-85B43AC43B08}.Release|Win32.ActiveCfg = Release|Win32 {56A9A4B2-21E5-4360-AFA8-85B43AC43B08}.Release|x64.ActiveCfg = Release|Win32 + {E4DF8176-4DEF-4859-962F-B497E3E7A323}.Debug|Win32.ActiveCfg = Debug|Win32 + {E4DF8176-4DEF-4859-962F-B497E3E7A323}.Debug|Win32.Build.0 = Debug|Win32 + {E4DF8176-4DEF-4859-962F-B497E3E7A323}.Debug|x64.ActiveCfg = Debug|Win32 + {E4DF8176-4DEF-4859-962F-B497E3E7A323}.Deploy|Win32.ActiveCfg = Debug|Win32 + {E4DF8176-4DEF-4859-962F-B497E3E7A323}.Deploy|Win32.Build.0 = Debug|Win32 + {E4DF8176-4DEF-4859-962F-B497E3E7A323}.Deploy|x64.ActiveCfg = Release|Win32 + {E4DF8176-4DEF-4859-962F-B497E3E7A323}.Deploy|x64.Build.0 = Release|Win32 + {E4DF8176-4DEF-4859-962F-B497E3E7A323}.Release|Win32.ActiveCfg = Release|Win32 + {E4DF8176-4DEF-4859-962F-B497E3E7A323}.Release|Win32.Build.0 = Release|Win32 + {E4DF8176-4DEF-4859-962F-B497E3E7A323}.Release|x64.ActiveCfg = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {E4DF8176-4DEF-4859-962F-B497E3E7A323} = {2F863EAD-33C9-4014-A573-93F085BA9CB1} + EndGlobalSection EndGlobal diff --git a/Telegram/MetaLang.pro b/Telegram/MetaLang.pro index dbef70ae9..0dfa29a6f 100644 --- a/Telegram/MetaLang.pro +++ b/Telegram/MetaLang.pro @@ -12,7 +12,7 @@ CONFIG(release, debug|release) { DESTDIR = ./../ReleaseLang } -CONFIG += plugin static +CONFIG += plugin static c++11 macx { QMAKE_INFO_PLIST = ./SourceFiles/_other/Lang.plist diff --git a/Telegram/MetaStyle.pro b/Telegram/MetaStyle.pro index 2ef67ea2e..a68a44385 100644 --- a/Telegram/MetaStyle.pro +++ b/Telegram/MetaStyle.pro @@ -12,7 +12,7 @@ CONFIG(release, debug|release) { DESTDIR = ./../ReleaseStyle } -CONFIG += plugin static +CONFIG += plugin static c++11 macx { QMAKE_INFO_PLIST = ./SourceFiles/_other/Style.plist diff --git a/Telegram/Resources/style.txt b/Telegram/Resources/style.txt index 02426507f..8c9251ad4 100644 --- a/Telegram/Resources/style.txt +++ b/Telegram/Resources/style.txt @@ -1052,8 +1052,8 @@ msgMinWidth: 190px; msgPhotoSize: 33px; msgPhotoSkip: 40px; msgPadding: margins(13px, 7px, 13px, 8px); -msgMargin: margins(13px, 6px, 53px, 2px); -msgMarginTopAttached: 2px; +msgMargin: margins(13px, 10px, 53px, 2px); +msgMarginTopAttached: 3px; msgLnkPadding: 2px; // for media open / save links msgBorder: #f0f0f0; msgInBg: #fff; @@ -1105,7 +1105,7 @@ msgServiceBg: #89a0b47f; msgServiceSelectBg: #bbc8d4a2; msgServiceColor: #FFF; msgServicePadding: margins(12px, 3px, 12px, 4px); -msgServiceMargin: margins(10px, 9px, 80px, 5px); +msgServiceMargin: margins(10px, 10px, 80px, 2px); msgColor: #000; msgDateColor: #000; @@ -1543,6 +1543,7 @@ reportSpamBg: #fffffff0; newMsgSound: ':/gui/art/newmsg.wav'; unreadBarHeight: 32px; +unreadBarMargin: 8px; unreadBarFont: semiboldFont; unreadBarBG: #fcfbfa; unreadBarBorder: shadowColor; diff --git a/Telegram/SourceFiles/app.cpp b/Telegram/SourceFiles/app.cpp index 29d48319f..751efd603 100644 --- a/Telegram/SourceFiles/app.cpp +++ b/Telegram/SourceFiles/app.cpp @@ -174,21 +174,19 @@ namespace App { return main() ? main()->api() : 0; } +namespace { bool loggedOut() { - Window *w(wnd()); if (cHasPasscode()) { cSetHasPasscode(false); } if (audioPlayer()) { audioPlayer()->stopAndClear(); } - if (w) { + if (Window *w = wnd()) { w->tempDirDelete(Local::ClearManagerAll); w->notifyClearFast(); w->setupIntro(true); } - MainWidget *m(main()); - if (m) m->destroyData(); MTP::authed(0); Local::reset(); @@ -199,13 +197,14 @@ namespace App { globalNotifyChatsPtr = UnknownNotifySettings; if (App::uploader()) App::uploader()->clear(); clearStorageImages(); - if (w) { + if (Window *w = wnd()) { w->getTitle()->updateBackButton(); w->updateTitleStatus(); w->getTitle()->resizeEvent(0); } return true; } +} // namespace void logOut() { if (MTP::started()) { @@ -431,13 +430,17 @@ namespace App { bool showPhone = !isServiceUser(data->id) && !d.is_self() && !d.is_contact() && !d.is_mutual_contact(); bool showPhoneChanged = !isServiceUser(data->id) && !d.is_self() && ((showPhone && data->contact) || (!showPhone && !data->contact)); + if (minimal) { + showPhoneChanged = false; + showPhone = !isServiceUser(data->id) && (data->id != peerFromUser(MTP::authedId())) && !data->contact; + } // see also Local::readPeer QString pname = (showPhoneChanged || phoneChanged || nameChanged) ? ((showPhone && !phone.isEmpty()) ? formatPhone(phone) : QString()) : data->nameOrPhone; if (!minimal && d.is_self() && uname != data->username) { - SignalHandlers::setSelfUsername(uname); + SignalHandlers::setCrashAnnotation("Username", uname); } data->setName(fname, lname, pname, uname); if (d.has_photo()) { @@ -1444,12 +1447,12 @@ namespace App { PeerData *peerByName(const QString &username) { QString uname(username.trimmed()); - for (PeersData::const_iterator i = peersData.cbegin(), e = peersData.cend(); i != e; ++i) { - if (!i.value()->userName().compare(uname, Qt::CaseInsensitive)) { - return i.value(); + for_const (PeerData *peer, peersData) { + if (!peer->userName().compare(uname, Qt::CaseInsensitive)) { + return peer; } } - return 0; + return nullptr; } void updateImage(ImagePtr &old, ImagePtr now) { @@ -1855,20 +1858,20 @@ namespace App { cSetSavedPeers(SavedPeers()); cSetSavedPeersByTime(SavedPeersByTime()); cSetRecentInlineBots(RecentInlineBots()); - for (PeersData::const_iterator i = peersData.cbegin(), e = peersData.cend(); i != e; ++i) { - delete *i; + for_const (PeerData *peer, peersData) { + delete peer; } peersData.clear(); - for (PhotosData::const_iterator i = ::photosData.cbegin(), e = ::photosData.cend(); i != e; ++i) { - delete *i; + for_const (PhotoData *photo, ::photosData) { + delete photo; } ::photosData.clear(); - for (DocumentsData::const_iterator i = ::documentsData.cbegin(), e = ::documentsData.cend(); i != e; ++i) { - delete *i; + for_const (DocumentData *document, ::documentsData) { + delete document; } ::documentsData.clear(); - for (WebPagesData::const_iterator i = webPagesData.cbegin(), e = webPagesData.cend(); i != e; ++i) { - delete *i; + for_const (WebPageData *webpage, webPagesData) { + delete webpage; } webPagesData.clear(); if (api()) api()->clearWebPageRequests(); diff --git a/Telegram/SourceFiles/app.h b/Telegram/SourceFiles/app.h index a4039571e..13deab017 100644 --- a/Telegram/SourceFiles/app.h +++ b/Telegram/SourceFiles/app.h @@ -56,7 +56,6 @@ namespace App { ApiWrap *api(); void logOut(); - bool loggedOut(); QString formatPhone(QString phone); diff --git a/Telegram/SourceFiles/codegen/style/main.cpp b/Telegram/SourceFiles/codegen/style/main.cpp new file mode 100644 index 000000000..a553b5173 --- /dev/null +++ b/Telegram/SourceFiles/codegen/style/main.cpp @@ -0,0 +1,3 @@ +int main(int argc, char *argv[]) { + return 0; +} diff --git a/Telegram/SourceFiles/config.h b/Telegram/SourceFiles/config.h index 39e5008f3..270dc855f 100644 --- a/Telegram/SourceFiles/config.h +++ b/Telegram/SourceFiles/config.h @@ -20,8 +20,8 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org */ #pragma once -static const int32 AppVersion = 9036; -static const wchar_t *AppVersionStr = L"0.9.36"; +static const int32 AppVersion = 9039; +static const wchar_t *AppVersionStr = L"0.9.39"; static const bool DevVersion = true; //#define BETA_VERSION (9034004ULL) // just comment this line to build public version diff --git a/Telegram/SourceFiles/dropdown.cpp b/Telegram/SourceFiles/dropdown.cpp index 23b138a26..bc74c48bc 100644 --- a/Telegram/SourceFiles/dropdown.cpp +++ b/Telegram/SourceFiles/dropdown.cpp @@ -941,6 +941,8 @@ void EmojiPanInner::selectEmoji(EmojiPtr emoji) { } void EmojiPanInner::onShowPicker() { + if (_pickerSel < 0) return; + int tab = (_pickerSel / MatrixRowShift), sel = _pickerSel % MatrixRowShift; if (tab < emojiTabCount && sel < _emojis[tab].size() && _emojis[tab][sel]->color) { int32 y = 0; diff --git a/Telegram/SourceFiles/facades.cpp b/Telegram/SourceFiles/facades.cpp index ebd738870..77e4fa986 100644 --- a/Telegram/SourceFiles/facades.cpp +++ b/Telegram/SourceFiles/facades.cpp @@ -120,6 +120,12 @@ namespace App { } } + void logOutDelayed() { + if (Window *w = App::wnd()) { + QMetaObject::invokeMethod(w, "onLogoutSure", Qt::QueuedConnection); + } + } + } namespace Ui { diff --git a/Telegram/SourceFiles/facades.h b/Telegram/SourceFiles/facades.h index d7b737112..ae0da4a5e 100644 --- a/Telegram/SourceFiles/facades.h +++ b/Telegram/SourceFiles/facades.h @@ -38,6 +38,9 @@ namespace App { void showSettings(); void activateClickHandler(ClickHandlerPtr handler, Qt::MouseButton button); + + void logOutDelayed(); + }; namespace Ui { diff --git a/Telegram/SourceFiles/gui/text.cpp b/Telegram/SourceFiles/gui/text.cpp index 63c363e30..0733302f4 100644 --- a/Telegram/SourceFiles/gui/text.cpp +++ b/Telegram/SourceFiles/gui/text.cpp @@ -3572,7 +3572,14 @@ TextBlock::TextBlock(const style::font &font, const QString &str, QFixed minResi layout.beginLayout(); layout.createLine(); + bool logCrashString = (rand_value() % 4 == 1); + if (logCrashString) { + SignalHandlers::setCrashAnnotationRef("CrashString", &part); + } BlockParser parser(&engine, this, minResizeWidth, _from, part); + if (logCrashString) { + SignalHandlers::clearCrashAnnotationRef("CrashString"); + } layout.endLayout(); } diff --git a/Telegram/SourceFiles/history.cpp b/Telegram/SourceFiles/history.cpp index a0d70ca21..068f9b3b8 100644 --- a/Telegram/SourceFiles/history.cpp +++ b/Telegram/SourceFiles/history.cpp @@ -377,11 +377,13 @@ bool History::updateTyping(uint64 ms, bool force) { return changed; } -ChannelHistory::ChannelHistory(const PeerId &peer) : History(peer), -unreadCountAll(0), -_onlyImportant(!isMegagroup()), -_otherOldLoaded(false), _otherNewLoaded(true), -_collapseMessage(0), _joinedMessage(0) { +ChannelHistory::ChannelHistory(const PeerId &peer) : History(peer) +, unreadCountAll(0) +, _onlyImportant(!isMegagroup()) +, _otherOldLoaded(false) +, _otherNewLoaded(true) +, _collapseMessage(nullptr) +, _joinedMessage(nullptr) { } bool ChannelHistory::isSwitchReadyFor(MsgId switchId, MsgId &fixInScrollMsgId, int32 &fixInScrollMsgTop) { @@ -575,14 +577,8 @@ void ChannelHistory::addNewGroup(const MTPMessageGroup &group) { if (onlyImportant()) { if (newLoaded) { - HistoryBlock *block = blocks.isEmpty() ? pushBackNewBlock() : blocks.back(); - HistoryItem *prev = block->items.isEmpty() ? nullptr : block->items.back(); - - prev = addMessageGroupAfterPrevToBlock(d, prev, block); - if (block->items.isEmpty()) { - blocks.pop_back(); - delete block; - } + t_assert(!isBuildingFrontBlock()); + addMessageGroup(d); } } else { setNotLoadedAtBottom(); @@ -639,14 +635,12 @@ HistoryJoined *ChannelHistory::insertJoinedMessage(bool unread) { } } - // adding new item to new block - HistoryBlock *block = pushFrontNewBlock(); + startBuildingFrontBlock(); _joinedMessage = HistoryJoined::create(this, inviteDate, inviter, flags); - addItemToBlock(_joinedMessage, block); + addItemToBlock(_joinedMessage); - t_assert(blocks.size() > 1); - blocks.at(1)->items.front()->previousItemChanged(); + finishBuildingFrontBlock(); return _joinedMessage; } @@ -755,15 +749,15 @@ HistoryItem *ChannelHistory::addNewToBlocks(const MTPMessage &msg, NewMessageTyp } if (!isImportant && onlyImportant()) { - HistoryItem *item = addToHistory(msg), *prev = isEmpty() ? nullptr : blocks.back()->items.back(); + HistoryItem *item = addToHistory(msg); + + t_assert(!isBuildingFrontBlock()); + addMessageGroup([item, this](HistoryItem *previous) -> HistoryGroup* { // create(..) + return HistoryGroup::create(this, item, previous ? previous->date : item->date); + }, [item](HistoryGroup *existing) { // unite(..) + existing->uniteWith(item); + }); - if (prev && prev->type() == HistoryItemGroup) { - static_cast(prev)->uniteWith(item); - } else { - QDateTime date = prev ? prev->date : item->date; - HistoryBlock *block = prev ? prev->block() : pushBackNewBlock(); - addItemToBlock(HistoryGroup::create(this, item, date), block); - } return item; } @@ -819,22 +813,15 @@ void ChannelHistory::switchMode() { clear(true); + t_assert(!isBuildingFrontBlock()); + newLoaded = _otherNewLoaded; oldLoaded = _otherOldLoaded; if (int count = _otherList.size()) { - blocks.reserve(qCeil(count / float64(MessagesPerPage))); - - for (int i = 0; i < count;) { - HistoryBlock *block = pushBackNewBlock(); - - int willAddToBlock = qMin(int(MessagesPerPage), count - i); - block->items.reserve(willAddToBlock); - for (int till = i + willAddToBlock; i < till; ++i) { - t_assert(_otherList.at(i)->detached()); - addItemToBlock(_otherList.at(i), block); - } - - t_assert(!block->items.isEmpty()); + blocks.reserve((count / MessagesPerPage) + 1); + for (int i = 0; i < count; ++i) { + t_assert(_otherList.at(i)->detached()); + addItemToBlock(_otherList.at(i)); } } @@ -1138,6 +1125,8 @@ void Histories::clear() { for (Map::const_iterator i = map.cbegin(), e = map.cend(); i != e; ++i) { delete i.value(); } + Global::RefPendingRepaintItems().clear(); + _unreadFull = _unreadMuted = 0; if (App::wnd()) { App::wnd()->updateCounter(); @@ -1545,16 +1534,10 @@ void History::eraseFromOverview(MediaOverviewType type, MsgId msgId) { } HistoryItem *History::addNewItem(HistoryItem *adding, bool newMsg) { - t_assert(adding != nullptr); - t_assert(adding->detached()); + t_assert(!isBuildingFrontBlock()); + addItemToBlock(adding); - HistoryBlock *block = blocks.isEmpty() ? pushBackNewBlock() : blocks.back(); - - adding->attachToBlock(block, block->items.size()); - block->items.push_back(adding); - adding->previousItemChanged(); setLastMessage(adding); - if (newMsg) { newItemAdded(adding); } @@ -1666,19 +1649,50 @@ void History::newItemAdded(HistoryItem *item) { } } -HistoryItem *History::addItemToBlock(HistoryItem *item, HistoryBlock *block) { +HistoryBlock *History::prepareBlockForAddingItem() { + if (isBuildingFrontBlock()) { + if (_buildingFrontBlock->block) { + return _buildingFrontBlock->block; + } + + HistoryBlock *result = _buildingFrontBlock->block = new HistoryBlock(this); + if (_buildingFrontBlock->expectedItemsCount > 0) { + result->items.reserve(_buildingFrontBlock->expectedItemsCount + 1); + } + result->setIndexInHistory(0); + blocks.push_front(result); + for (int i = 1, l = blocks.size(); i < l; ++i) { + blocks.at(i)->setIndexInHistory(i); + } + return result; + } + + bool addNewBlock = blocks.isEmpty() || (blocks.back()->items.size() >= MessagesPerPage); + if (!addNewBlock) { + return blocks.back(); + } + + HistoryBlock *result = new HistoryBlock(this); + result->setIndexInHistory(blocks.size()); + blocks.push_back(result); + + result->items.reserve(MessagesPerPage); + return result; +}; + +void History::addItemToBlock(HistoryItem *item) { + t_assert(item != nullptr); + t_assert(item->detached()); + + HistoryBlock *block = prepareBlockForAddingItem(); + item->attachToBlock(block, block->items.size()); block->items.push_back(item); item->previousItemChanged(); - return item; -} -HistoryItem *History::addMessageGroupAfterPrevToBlock(const MTPDmessageGroup &group, HistoryItem *prev, HistoryBlock *block) { - if (prev && prev->type() == HistoryItemGroup) { - static_cast(prev)->uniteWith(group.vmin_id.v, group.vmax_id.v, group.vcount.v); - return prev; + if (isBuildingFrontBlock() && _buildingFrontBlock->expectedItemsCount > 0) { + --_buildingFrontBlock->expectedItemsCount; } - return addItemToBlock(HistoryGroup::create(this, group, prev ? prev->date : date(group.vdate)), block); } void History::addOlderSlice(const QVector &slice, const QVector *collapsed) { @@ -1695,10 +1709,8 @@ void History::addOlderSlice(const QVector &slice, const QVectorconstData() : 0, *groupsIt = groupsBegin, *groupsEnd = (isChannel() && collapsed) ? (groupsBegin + collapsed->size()) : 0; - HistoryItem *prev = nullptr; - HistoryBlock *block = pushFrontNewBlock(); + startBuildingFrontBlock(slice.size() + (collapsed ? collapsed->size() : 0)); - block->items.reserve(slice.size() + (collapsed ? collapsed->size() : 0)); for (auto i = slice.cend(), e = slice.cbegin(); i != e;) { --i; HistoryItem *adding = createItem(*i, false, true); @@ -1709,23 +1721,21 @@ void History::addOlderSlice(const QVector &slice, const QVectorc_messageGroup()); if (group.vmin_id.v >= adding->id) break; - prev = addMessageGroupAfterPrevToBlock(group, prev, block); + addMessageGroup(group); } - prev = addItemToBlock(adding, block); + addItemToBlock(adding); } for (; groupsIt != groupsEnd; ++groupsIt) { if (groupsIt->type() != mtpc_messageGroup) continue; const MTPDmessageGroup &group(groupsIt->c_messageGroup()); - prev = addMessageGroupAfterPrevToBlock(group, prev, block); + addMessageGroup(group); } - if (block->items.isEmpty()) { - blocks.pop_front(); - delete block; - block = nullptr; - + HistoryBlock *block = finishBuildingFrontBlock(); + if (!block) { + // If no items were added it means we've loaded everything old. oldLoaded = true; } else if (loadedAtBottom()) { // add photos to overview and authors to lastAuthors / lastParticipants bool channel = isChannel(); @@ -1803,28 +1813,6 @@ void History::addOlderSlice(const QVector &slice, const QVector 1) { - HistoryItem *last = block->items.back(); // ... item, item, item, last ], [ first, item, item ... - HistoryItem *first = blocks.at(1)->items.front(); - - // we've added a new front block, so previous item for - // the old first item of a first block was changed - first->previousItemChanged(); - - // we've added a new front block, now we check if both - // last message of the first block and first message of - // the second block are groups, if they are - unite them - if (first->type() == HistoryItemGroup && last->type() == HistoryItemGroup) { - static_cast(first)->uniteWith(static_cast(last)); - last->destroy(); - - // last->destroy() could've destroyed this new block - // so we can't rely on this pointer any more - block = nullptr; - } - } - if (isChannel()) { asChannelHistory()->checkJoinedMessage(); asChannelHistory()->checkMaxReadMessageDate(); @@ -1840,14 +1828,11 @@ void History::addNewerSlice(const QVector &slice, const QVectorisEmpty())) { const MTPMessageGroup *groupsBegin = (isChannel() && collapsed) ? collapsed->constData() : 0, *groupsIt = groupsBegin, *groupsEnd = (isChannel() && collapsed) ? (groupsBegin + collapsed->size()) : 0; - HistoryItem *prev = blocks.isEmpty() ? nullptr : blocks.back()->items.back(); - - HistoryBlock *block = pushBackNewBlock(); - - block->items.reserve(slice.size() + (collapsed ? collapsed->size() : 0)); + bool atLeastOneAdded = false; for (auto i = slice.cend(), e = slice.cbegin(); i != e;) { --i; HistoryItem *adding = createItem(*i, false, true); @@ -1858,25 +1843,22 @@ void History::addNewerSlice(const QVector &slice, const QVectorc_messageGroup()); if (group.vmin_id.v >= adding->id) break; - prev = addMessageGroupAfterPrevToBlock(group, prev, block); + addMessageGroup(group); } - prev = addItemToBlock(adding, block); + addItemToBlock(adding); + atLeastOneAdded = true; } for (; groupsIt != groupsEnd; ++groupsIt) { if (groupsIt->type() != mtpc_messageGroup) continue; const MTPDmessageGroup &group(groupsIt->c_messageGroup()); - prev = addMessageGroupAfterPrevToBlock(group, prev, block); + addMessageGroup(group); } - if (block->items.isEmpty()) { + if (!atLeastOneAdded) { newLoaded = true; setLastMessage(lastImportantMessage()); - - blocks.pop_back(); - delete block; - block = nullptr; } } @@ -2176,21 +2158,70 @@ HistoryItem *History::addNewInTheMiddle(HistoryItem *newItem, int32 blockIndex, return newItem; } -HistoryBlock *History::pushBackNewBlock() { - HistoryBlock *result = new HistoryBlock(this); - result->setIndexInHistory(blocks.size()); - blocks.push_back(result); - return result; +template +void History::addMessageGroup(CreateGroup create, UniteGroup unite) { + HistoryItem *previous = nullptr; + if (isBuildingFrontBlock()) { + if (_buildingFrontBlock->block) { + previous = _buildingFrontBlock->block->items.back(); + } + } else { + if (!blocks.isEmpty()) { + previous = blocks.back()->items.back(); + } + } + + if (previous && previous->type() == HistoryItemGroup) { + unite(static_cast(previous)); + } else { + addItemToBlock(create(previous)); + } } -HistoryBlock *History::pushFrontNewBlock() { - HistoryBlock *result = new HistoryBlock(this); - result->setIndexInHistory(0); - blocks.push_front(result); - for (int i = 1, l = blocks.size(); i < l; ++i) { - blocks.at(i)->setIndexInHistory(i); +void History::addMessageGroup(const MTPDmessageGroup &group) { + addMessageGroup([&group, this](HistoryItem *previous) -> HistoryGroup* { // create(..) + return HistoryGroup::create(this, group, previous ? previous->date : date(group.vdate)); + }, [&group](HistoryGroup *existing) { // unite(..) + existing->uniteWith(group.vmin_id.v, group.vmax_id.v, group.vcount.v); + }); +} + +void History::startBuildingFrontBlock(int expectedItemsCount) { + t_assert(!isBuildingFrontBlock()); + t_assert(expectedItemsCount > 0); + + _buildingFrontBlock.reset(new BuildingBlock()); + _buildingFrontBlock->expectedItemsCount = expectedItemsCount; +} + +HistoryBlock *History::finishBuildingFrontBlock() { + t_assert(isBuildingFrontBlock()); + + // Some checks if there was some message history already + HistoryBlock *block = _buildingFrontBlock->block; + if (block && blocks.size() > 1) { + HistoryItem *last = block->items.back(); // ... item, item, item, last ], [ first, item, item ... + HistoryItem *first = blocks.at(1)->items.front(); + + // we've added a new front block, so previous item for + // the old first item of a first block was changed + first->previousItemChanged(); + + // we've added a new front block, now we check if both + // last message of the first block and first message of + // the second block are groups, if they are - unite them + if (first->type() == HistoryItemGroup && last->type() == HistoryItemGroup) { + static_cast(first)->uniteWith(static_cast(last)); + last->destroy(); + + // last->destroy() could've destroyed this new block + // so we can't rely on this pointer any more + block = _buildingFrontBlock->block; + } } - return result; + + _buildingFrontBlock.clear(); + return block; } void History::clearNotifications() { @@ -2567,6 +2598,10 @@ void History::changeMsgId(MsgId oldId, MsgId newId) { void History::removeBlock(HistoryBlock *block) { t_assert(block->items.isEmpty()); + if (_buildingFrontBlock && block == _buildingFrontBlock->block) { + _buildingFrontBlock->block = nullptr; + } + int index = block->indexInHistory(); blocks.removeAt(index); for (int i = index, l = blocks.size(); i < l; ++i) { @@ -3017,13 +3052,17 @@ void HistoryMessageUnreadBar::init(int count) { _width = st::semiboldFont->width(_text); } -int HistoryMessageUnreadBar::height() const { - return st::unreadBarHeight; +int HistoryMessageUnreadBar::height() { + return st::unreadBarHeight + st::unreadBarMargin; +} + +int HistoryMessageUnreadBar::marginTop() { + return st::lineWidth + st::unreadBarMargin; } void HistoryMessageUnreadBar::paint(Painter &p, int y, int w) const { - p.fillRect(0, y + st::lineWidth, w, st::unreadBarHeight - 2 * st::lineWidth, st::unreadBarBG); - p.fillRect(0, y + st::unreadBarHeight - st::lineWidth, w, st::lineWidth, st::unreadBarBorder); + p.fillRect(0, y + marginTop(), w, height() - marginTop() - st::lineWidth, st::unreadBarBG); + p.fillRect(0, y + height() - st::lineWidth, w, st::lineWidth, st::unreadBarBorder); p.setFont(st::unreadBarFont); p.setPen(st::unreadBarColor); @@ -3034,7 +3073,7 @@ void HistoryMessageUnreadBar::paint(Painter &p, int y, int w) const { } w = maxwidth; - p.drawText((w - _width) / 2, y + (st::unreadBarHeight - st::lineWidth - st::unreadBarFont->height) / 2 + st::unreadBarFont->ascent, _text); + p.drawText((w - _width) / 2, y + marginTop() + (st::unreadBarHeight - 2 * st::lineWidth - st::unreadBarFont->height) / 2 + st::unreadBarFont->ascent, _text); } void HistoryMessageDate::init(const QDateTime &date) { @@ -3128,6 +3167,7 @@ void HistoryItem::destroy() { if ((!out() || isPost()) && unread() && history()->unreadCount > 0) { history()->setUnreadCount(history()->unreadCount - 1); } + Global::RefPendingRepaintItems().remove(this); delete this; } @@ -3334,7 +3374,7 @@ void RadialAnimation::update(float64 prg, bool finished, uint64 ms) { _opacity *= 1 - r; } float64 fromstart = fulldt / st::radialPeriod; - a_arcStart.update(fromstart - qFloor(fromstart), anim::linear); + a_arcStart.update(fromstart - std::floor(fromstart), anim::linear); } void RadialAnimation::stop() { @@ -5155,7 +5195,7 @@ void HistorySticker::draw(Painter &p, const HistoryItem *parent, const QRect &r, } if (parent->getMedia() == this) { - parent->drawInfo(p, usex + usew, _height, usex * 2 + usew, selected, InfoDisplayOverImage); + parent->drawInfo(p, usex + usew, _height, usex * 2 + usew, selected, InfoDisplayOverBackground); if (reply) { int32 rw = _width - usew - st::msgReplyPadding.left(), rh = st::msgReplyPadding.top() + st::msgReplyBarSize.height() + st::msgReplyPadding.bottom(); @@ -6996,18 +7036,24 @@ bool HistoryMessage::textHasLinks() { void HistoryMessage::drawInfo(Painter &p, int32 right, int32 bottom, int32 width, bool selected, InfoDisplayType type) const { p.setFont(st::msgDateFont); - bool outbg = out() && !isPost(), overimg = (type == InfoDisplayOverImage); + bool outbg = out() && !isPost(); + bool invertedsprites = (type == InfoDisplayOverImage || type == InfoDisplayOverBackground); int32 infoRight = right, infoBottom = bottom; switch (type) { case InfoDisplayDefault: infoRight -= st::msgPadding.right() - st::msgDateDelta.x(); infoBottom -= st::msgPadding.bottom() - st::msgDateDelta.y(); - p.setPen((selected ? (outbg ? st::msgOutDateFgSelected : st::msgInDateFgSelected) : (outbg ? st::msgOutDateFg : st::msgInDateFg))->p); + p.setPen(selected ? (outbg ? st::msgOutDateFgSelected : st::msgInDateFgSelected) : (outbg ? st::msgOutDateFg : st::msgInDateFg)); break; case InfoDisplayOverImage: infoRight -= st::msgDateImgDelta + st::msgDateImgPadding.x(); infoBottom -= st::msgDateImgDelta + st::msgDateImgPadding.y(); - p.setPen(st::msgDateImgColor->p); + p.setPen(st::msgDateImgColor); + break; + case InfoDisplayOverBackground: + infoRight -= st::msgDateImgDelta + st::msgDateImgPadding.x(); + infoBottom -= st::msgDateImgDelta + st::msgDateImgPadding.y(); + p.setPen(st::msgServiceColor); break; } @@ -7019,6 +7065,9 @@ void HistoryMessage::drawInfo(Painter &p, int32 right, int32 bottom, int32 width if (type == InfoDisplayOverImage) { int32 dateW = infoW + 2 * st::msgDateImgPadding.x(), dateH = st::msgDateFont->height + 2 * st::msgDateImgPadding.y(); App::roundRect(p, dateX - st::msgDateImgPadding.x(), dateY - st::msgDateImgPadding.y(), dateW, dateH, selected ? st::msgDateImgBgSelected : st::msgDateImgBg, selected ? DateSelectedCorners : DateCorners); + } else if (type == InfoDisplayOverBackground) { + int32 dateW = infoW + 2 * st::msgDateImgPadding.x(), dateH = st::msgDateFont->height + 2 * st::msgDateImgPadding.y(); + App::roundRect(p, dateX - st::msgDateImgPadding.x(), dateY - st::msgDateImgPadding.y(), dateW, dateH, App::msgServiceBg(), ServiceCorners); } dateX += HistoryMessage::timeLeft(); @@ -7034,35 +7083,35 @@ void HistoryMessage::drawInfo(Painter &p, int32 right, int32 bottom, int32 width iconPos = QPoint(infoRight - infoW + st::msgViewsPos.x(), infoBottom - st::msgViewsImg.pxHeight() + st::msgViewsPos.y()); if (id > 0) { if (outbg) { - iconRect = &(overimg ? st::msgInvViewsImg : (selected ? st::msgSelectOutViewsImg : st::msgOutViewsImg)); + iconRect = &(invertedsprites ? st::msgInvViewsImg : (selected ? st::msgSelectOutViewsImg : st::msgOutViewsImg)); } else { - iconRect = &(overimg ? st::msgInvViewsImg : (selected ? st::msgSelectViewsImg : st::msgViewsImg)); + iconRect = &(invertedsprites ? st::msgInvViewsImg : (selected ? st::msgSelectViewsImg : st::msgViewsImg)); } p.drawText(iconPos.x() + st::msgViewsImg.pxWidth() + st::msgDateCheckSpace, infoBottom - st::msgDateFont->descent, views->_viewsText); } else { iconPos.setX(iconPos.x() + st::msgDateViewsSpace + views->_viewsWidth); if (outbg) { - iconRect = &(overimg ? st::msgInvSendingViewsImg : st::msgSendingOutViewsImg); + iconRect = &(invertedsprites ? st::msgInvSendingViewsImg : st::msgSendingOutViewsImg); } else { - iconRect = &(overimg ? st::msgInvSendingViewsImg : st::msgSendingViewsImg); + iconRect = &(invertedsprites ? st::msgInvSendingViewsImg : st::msgSendingViewsImg); } } p.drawPixmap(iconPos, App::sprite(), *iconRect); } else if (id < 0 && history()->peer->isSelf()) { iconPos = QPoint(infoRight - infoW, infoBottom - st::msgViewsImg.pxHeight() + st::msgViewsPos.y()); - iconRect = &(overimg ? st::msgInvSendingViewsImg : st::msgSendingViewsImg); + iconRect = &(invertedsprites ? st::msgInvSendingViewsImg : st::msgSendingViewsImg); p.drawPixmap(iconPos, App::sprite(), *iconRect); } if (outbg) { iconPos = QPoint(infoRight - st::msgCheckImg.pxWidth() + st::msgCheckPos.x(), infoBottom - st::msgCheckImg.pxHeight() + st::msgCheckPos.y()); if (id > 0) { if (unread()) { - iconRect = &(overimg ? st::msgInvCheckImg : (selected ? st::msgSelectCheckImg : st::msgCheckImg)); + iconRect = &(invertedsprites ? st::msgInvCheckImg : (selected ? st::msgSelectCheckImg : st::msgCheckImg)); } else { - iconRect = &(overimg ? st::msgInvDblCheckImg : (selected ? st::msgSelectDblCheckImg : st::msgDblCheckImg)); + iconRect = &(invertedsprites ? st::msgInvDblCheckImg : (selected ? st::msgSelectDblCheckImg : st::msgDblCheckImg)); } } else { - iconRect = &(overimg ? st::msgInvSendingImg : st::msgSendingImg); + iconRect = &(invertedsprites ? st::msgInvSendingImg : st::msgSendingImg); } p.drawPixmap(iconPos, App::sprite(), *iconRect); } diff --git a/Telegram/SourceFiles/history.h b/Telegram/SourceFiles/history.h index 70db17196..34669f3f0 100644 --- a/Telegram/SourceFiles/history.h +++ b/Telegram/SourceFiles/history.h @@ -470,19 +470,64 @@ protected: void clearOnDestroy(); HistoryItem *addNewToLastBlock(const MTPMessage &msg, NewMessageType type); + friend class HistoryBlock; + + // this method just removes a block from the blocks list + // when the last item from this block was detached and + // calls the required previousItemChanged() + void removeBlock(HistoryBlock *block); + + void clearBlocks(bool leaveItems); + + HistoryItem *createItem(const MTPMessage &msg, bool applyServiceAction, bool detachExistingItem); + HistoryItem *createItemForwarded(MsgId id, MTPDmessage::Flags flags, QDateTime date, int32 from, HistoryMessage *msg); + HistoryItem *createItemDocument(MsgId id, MTPDmessage::Flags flags, int32 viaBotId, MsgId replyTo, QDateTime date, int32 from, DocumentData *doc, const QString &caption); + HistoryItem *createItemPhoto(MsgId id, MTPDmessage::Flags flags, int32 viaBotId, MsgId replyTo, QDateTime date, int32 from, PhotoData *photo, const QString &caption); + + HistoryItem *addNewItem(HistoryItem *adding, bool newMsg); + HistoryItem *addNewInTheMiddle(HistoryItem *newItem, int32 blockIndex, int32 itemIndex); + + // All this methods add a new item to the first or last block + // depending on if we are in isBuildingFronBlock() state. + // The last block is created on the go if it is needed. + + // If the previous item is a message group the new group is + // not created but is just united with the previous one. + // create(HistoryItem *previous) should return a new HistoryGroup* + // unite(HistoryGroup *existing) should unite a new group with an existing + template + void addMessageGroup(CreateGroup create, UniteGroup unite); + void addMessageGroup(const MTPDmessageGroup &group); + + // Adds the item to the back or front block, depending on + // isBuildingFrontBlock(), creating the block if necessary. + void addItemToBlock(HistoryItem *item); + + // Usually all new items are added to the last block. + // Only when we scroll up and add a new slice to the + // front we want to create a new front block. + void startBuildingFrontBlock(int expectedItemsCount = 1); + HistoryBlock *finishBuildingFrontBlock(); // Returns the built block or nullptr if nothing was added. + bool isBuildingFrontBlock() const { + return !_buildingFrontBlock.isNull(); + } + private: - enum Flag { + enum class Flag { f_has_pending_resized_items = (1 << 0), - f_pending_resize = (1 << 1), + f_pending_resize = (1 << 1), }; Q_DECLARE_FLAGS(Flags, Flag); - Q_DECL_CONSTEXPR friend inline QFlags operator|(Flags::enum_type f1, Flags::enum_type f2) Q_DECL_NOTHROW { + Q_DECL_CONSTEXPR friend inline QFlags operator|(Flags::enum_type f1, Flags::enum_type f2) noexcept { return QFlags(f1) | f2; } - Q_DECL_CONSTEXPR friend inline QFlags operator|(Flags::enum_type f1, QFlags f2) Q_DECL_NOTHROW { + Q_DECL_CONSTEXPR friend inline QFlags operator|(Flags::enum_type f1, QFlags f2) noexcept { return f2 | f1; } + Q_DECL_CONSTEXPR friend inline QFlags operator~(Flags::enum_type f) noexcept { + return ~QFlags(f); + } Flags _flags; ChatListLinksMap _chatListLinks; @@ -497,28 +542,18 @@ private: MediaOverviewIds overviewIds[OverviewCount]; int32 overviewCountData[OverviewCount]; // -1 - not loaded, 0 - all loaded, > 0 - count, but not all loaded - friend class HistoryBlock; - friend class ChannelHistory; + // A pointer to the block that is currently being built. + // We hold this pointer so we can destroy it while building + // and then create a new one if it is necessary. + struct BuildingBlock { + int expectedItemsCount = 0; // optimization for block->items.reserve() call + HistoryBlock *block = nullptr; + }; + UniquePointer _buildingFrontBlock; - // this method just removes a block from the blocks list - // when the last item from this block was detached and - // calls the required previousItemChanged() - void removeBlock(HistoryBlock *block); - - void clearBlocks(bool leaveItems); - - HistoryItem *createItem(const MTPMessage &msg, bool applyServiceAction, bool detachExistingItem); - HistoryItem *createItemForwarded(MsgId id, MTPDmessage::Flags flags, QDateTime date, int32 from, HistoryMessage *msg); - HistoryItem *createItemDocument(MsgId id, MTPDmessage::Flags flags, int32 viaBotId, MsgId replyTo, QDateTime date, int32 from, DocumentData *doc, const QString &caption); - HistoryItem *createItemPhoto(MsgId id, MTPDmessage::Flags flags, int32 viaBotId, MsgId replyTo, QDateTime date, int32 from, PhotoData *photo, const QString &caption); - - HistoryItem *addItemToBlock(HistoryItem *item, HistoryBlock *block); - HistoryItem *addNewItem(HistoryItem *adding, bool newMsg); - HistoryItem *addMessageGroupAfterPrevToBlock(const MTPDmessageGroup &group, HistoryItem *prev, HistoryBlock *block); - HistoryItem *addNewInTheMiddle(HistoryItem *newItem, int32 blockIndex, int32 itemIndex); - - HistoryBlock *pushBackNewBlock(); - HistoryBlock *pushFrontNewBlock(); + // Creates if necessary a new block for adding item. + // Depending on isBuildingFrontBlock() gets front or back block. + HistoryBlock *prepareBlockForAddingItem(); }; @@ -952,6 +987,7 @@ enum HistoryCursorState { enum InfoDisplayType { InfoDisplayDefault, InfoDisplayOverImage, + InfoDisplayOverBackground, }; inline bool isImportantChannelMessage(MsgId id, MTPDmessage::Flags flags) { // client-side important msgs always has_views or has_from_id @@ -1232,7 +1268,9 @@ struct HistoryMessageDate : public BaseComponent { struct HistoryMessageUnreadBar : public BaseComponent { void init(int count); - int height() const; + static int height(); + static int marginTop(); + void paint(Painter &p, int y, int w) const; QString _text; @@ -1695,8 +1733,11 @@ protected: HistoryItem *previous() const { if (_block && _indexInBlock >= 0) { - if (_indexInBlock > 0) return _block->items.at(_indexInBlock - 1); + if (_indexInBlock > 0) { + return _block->items.at(_indexInBlock - 1); + } if (HistoryBlock *previousBlock = _block->previous()) { + t_assert(!previousBlock->items.isEmpty()); return previousBlock->items.back(); } } diff --git a/Telegram/SourceFiles/historywidget.cpp b/Telegram/SourceFiles/historywidget.cpp index 55a7960da..4a4de8adc 100644 --- a/Telegram/SourceFiles/historywidget.cpp +++ b/Telegram/SourceFiles/historywidget.cpp @@ -190,9 +190,17 @@ void HistoryInner::enumerateUserpicsInHistory(History *h, int htop, Method metho } void HistoryInner::paintEvent(QPaintEvent *e) { - if (App::wnd() && App::wnd()->contentOverlapped(this, e)) return; + if (App::wnd() && App::wnd()->contentOverlapped(this, e)) { + return; + } - if (!App::main()) return; + if (!App::main()) { + return; + } + + if ((_history && _history->hasPendingResizedItems()) || (_migrated && _migrated->hasPendingResizedItems())) { + return; + } Painter p(this); QRect r(e->rect()); @@ -1643,7 +1651,9 @@ void HistoryInner::onTouchSelect() { } void HistoryInner::onUpdateSelected() { - if (!_history) return; + if (!_history || _history->hasPendingResizedItems() || (_migrated && _migrated->hasPendingResizedItems())) { + return; + } QPoint mousePos(mapFromGlobal(_dragPos)); QPoint point(_widget->clampMousePosition(mousePos)); @@ -6178,7 +6188,7 @@ void HistoryWidget::notify_automaticLoadSettingsChangedGif() { } void HistoryWidget::notify_handlePendingHistoryUpdate() { - if (_history && _history->hasPendingResizedItems()) { + if ((_history && _history->hasPendingResizedItems()) || (_migrated && _migrated->hasPendingResizedItems())) { updateListSize(); _list->update(); } @@ -6324,7 +6334,9 @@ void HistoryWidget::updateListSize(bool initial, bool loadedDown, const ScrollCh if (_pinnedBar) { newScrollHeight -= st::replyHeight; } - bool wasAtBottom = _scroll.scrollTop() + 1 > _scroll.scrollTopMax(), needResize = _scroll.width() != width() || _scroll.height() != newScrollHeight; + int wasScrollTop = _scroll.scrollTop(); + bool wasAtBottom = wasScrollTop + 1 > _scroll.scrollTopMax(); + bool needResize = (_scroll.width() != width()) || (_scroll.height() != newScrollHeight); if (needResize) { _scroll.resize(width(), newScrollHeight); // on initial updateListSize we didn't put the _scroll.scrollTop correctly yet @@ -6350,14 +6362,15 @@ void HistoryWidget::updateListSize(bool initial, bool loadedDown, const ScrollCh } if ((!initial && !wasAtBottom) || (loadedDown && (!_history->showFrom || _history->unreadBar || _history->loadedAtBottom()) && (!_migrated || !_migrated->showFrom || _migrated->unreadBar || _history->loadedAtBottom()))) { - int addToY = 0; + int toY = _list->historyScrollTop(); if (change.type == ScrollChangeAdd) { - addToY = change.value; - } else if (change.type == ScrollChangeOldHistoryHeight) { - addToY = _list->historyHeight() - change.value; + toY += change.value; + } else if (change.type == ScrollChangeNoJumpToBottom) { + toY = wasScrollTop; + } + if (toY > _scroll.scrollTopMax()) { + toY = _scroll.scrollTopMax(); } - int toY = _list->historyScrollTop() + addToY; - if (toY > _scroll.scrollTopMax()) toY = _scroll.scrollTopMax(); if (_scroll.scrollTop() == toY) { visibleAreaUpdated(); } else { @@ -6435,13 +6448,11 @@ void HistoryWidget::updateListSize(bool initial, bool loadedDown, const ScrollCh } else { toY = qMax(iy + item->height() - _fixedInScrollMsgTop, 0); } - } else if (initial && _migrated && _migrated->unreadBar) { - toY = _list->itemTop(_migrated->unreadBar); - } else if (initial && _history->unreadBar) { - toY = _list->itemTop(_history->unreadBar); + } else if (initial && (_history->unreadBar || (_migrated && _migrated->unreadBar))) { + toY = unreadBarTop(); } else if (_migrated && _migrated->showFrom) { toY = _list->itemTop(_migrated->showFrom); - if (toY < _scroll.scrollTopMax() + st::unreadBarHeight) { + if (toY < _scroll.scrollTopMax() + HistoryMessageUnreadBar::height() - HistoryMessageUnreadBar::marginTop()) { _migrated->addUnreadBar(); if (_migrated->unreadBar) { setMsgId(ShowAtUnreadMsgId); @@ -6473,6 +6484,26 @@ void HistoryWidget::updateListSize(bool initial, bool loadedDown, const ScrollCh } } +int HistoryWidget::unreadBarTop() const { + auto getUnreadBar = [this]() -> HistoryItem* { + if (_migrated && _migrated->unreadBar) { + return _migrated->unreadBar; + } + if (_history->unreadBar) { + return _history->unreadBar; + } + return nullptr; + }; + if (HistoryItem *bar = getUnreadBar()) { + int result = _list->itemTop(bar) + HistoryMessageUnreadBar::marginTop(); + if (bar->Has()) { + result += bar->Get()->height(); + } + return result; + } + return -1; +} + void HistoryWidget::addMessagesToFront(PeerData *peer, const QVector &messages, const QVector *collapsed) { int oldH = _list->historyHeight(); _list->messagesReceived(peer, messages, collapsed); @@ -6491,7 +6522,7 @@ void HistoryWidget::addMessagesToFront(PeerData *peer, const QVector void HistoryWidget::addMessagesToBack(PeerData *peer, const QVector &messages, const QVector *collapsed) { _list->messagesReceivedDown(peer, messages, collapsed); if (!_firstLoadRequest) { - updateListSize(false, true); + updateListSize(false, true, { ScrollChangeNoJumpToBottom, 0 }); } } @@ -6875,7 +6906,10 @@ bool HistoryWidget::pinnedMsgVisibilityUpdated() { _topShadow.raise(); updatePinnedBar(); result = true; - _scroll.scrollToY(_scroll.scrollTop() + st::replyHeight); + + if (_scroll.scrollTop() != unreadBarTop()) { + _scroll.scrollToY(_scroll.scrollTop() + st::replyHeight); + } } else if (_pinnedBar->msgId != pinnedMsgId) { _pinnedBar->msgId = pinnedMsgId; _pinnedBar->msg = 0; @@ -6889,7 +6923,9 @@ bool HistoryWidget::pinnedMsgVisibilityUpdated() { } else if (_pinnedBar) { destroyPinnedBar(); result = true; - _scroll.scrollToY(_scroll.scrollTop() - st::replyHeight); + if (_scroll.scrollTop() != unreadBarTop()) { + _scroll.scrollToY(_scroll.scrollTop() - st::replyHeight); + } resizeEvent(0); } return result; diff --git a/Telegram/SourceFiles/historywidget.h b/Telegram/SourceFiles/historywidget.h index f91a1fbf2..79e58401c 100644 --- a/Telegram/SourceFiles/historywidget.h +++ b/Telegram/SourceFiles/historywidget.h @@ -864,8 +864,12 @@ private: enum ScrollChangeType { ScrollChangeNone, + + // When we toggle a pinned message. ScrollChangeAdd, - ScrollChangeOldHistoryHeight, + + // When loading a history part while scrolling down. + ScrollChangeNoJumpToBottom, }; struct ScrollChange { ScrollChangeType type; @@ -873,6 +877,10 @@ private: }; void updateListSize(bool initial = false, bool loadedDown = false, const ScrollChange &change = { ScrollChangeNone, 0 }); + // Counts scrollTop for placing the scroll right at the unread + // messages bar, choosing from _history and _migrated unreadBar. + int unreadBarTop() const; + void saveGifDone(DocumentData *doc, const MTPBool &result); void reportSpamDone(PeerData *peer, const MTPBool &result, mtpRequestId request); diff --git a/Telegram/SourceFiles/logs.cpp b/Telegram/SourceFiles/logs.cpp index 68fa217d0..0040b4f1b 100644 --- a/Telegram/SourceFiles/logs.cpp +++ b/Telegram/SourceFiles/logs.cpp @@ -614,119 +614,127 @@ void _moveOldDataFiles(const QString &wasDir) { namespace SignalHandlers { - typedef std::map AnnotationsMap; - AnnotationsMap ProcessAnnotations; +namespace internal { + using Annotations = std::map; + using AnnotationRefs = std::map; + + Annotations ProcessAnnotations; + AnnotationRefs ProcessAnnotationRefs; #ifndef TDESKTOP_DISABLE_CRASH_REPORTS - QString CrashDumpPath; - FILE *CrashDumpFile = nullptr; - int CrashDumpFileNo = 0; + QString ReportPath; + FILE *ReportFile = nullptr; + int ReportFileNo = 0; char LaunchedDateTimeStr[32] = { 0 }; char LaunchedBinaryName[256] = { 0 }; - void _writeChar(char ch) { - fwrite(&ch, 1, 1, CrashDumpFile); + void writeChar(char ch) { + fwrite(&ch, 1, 1, ReportFile); } - dump::~dump() { - if (CrashDumpFile) { - fflush(CrashDumpFile); - } - } - - const dump &operator<<(const dump &stream, const char *str) { - if (!CrashDumpFile) return stream; - - fwrite(str, 1, strlen(str), CrashDumpFile); - return stream; - } - - const dump &operator<<(const dump &stream, const wchar_t *str) { - if (!CrashDumpFile) return stream; - - for (int i = 0, l = wcslen(str); i < l; ++i) { - if (str[i] >= 0 && str[i] < 128) { - _writeChar(char(str[i])); - } else { - _writeChar('?'); - } - } - return stream; - } - template - struct _writeNumberSignAndRemoveIt { + struct writeNumberSignAndRemoveIt { static void call(Type &number) { if (number < 0) { - _writeChar('-'); + writeChar('-'); number = -number; } } }; template - struct _writeNumberSignAndRemoveIt { + struct writeNumberSignAndRemoveIt { static void call(Type &number) { } }; template - const dump &_writeNumber(const dump &stream, Type number) { - if (!CrashDumpFile) return stream; + const dump &writeNumber(const dump &stream, Type number) { + if (!ReportFile) return stream; - _writeNumberSignAndRemoveIt<(Type(-1) > Type(0)), Type>::call(number); + writeNumberSignAndRemoveIt<(Type(-1) > Type(0)), Type>::call(number); Type upper = 1, prev = number / 10; while (prev >= upper) { upper *= 10; } while (upper > 0) { int digit = (number / upper); - _writeChar('0' + digit); + internal::writeChar('0' + digit); number -= digit * upper; upper /= 10; } return stream; } +} // namespace internal + + dump::~dump() { + if (internal::ReportFile) { + fflush(internal::ReportFile); + } + } + + const dump &operator<<(const dump &stream, const char *str) { + if (!internal::ReportFile) return stream; + + fwrite(str, 1, strlen(str), internal::ReportFile); + return stream; + } + + const dump &operator<<(const dump &stream, const wchar_t *str) { + if (!internal::ReportFile) return stream; + + for (int i = 0, l = wcslen(str); i < l; ++i) { + if (str[i] >= 0 && str[i] < 128) { + internal::writeChar(char(str[i])); + } else { + internal::writeChar('?'); + } + } + return stream; + } + const dump &operator<<(const dump &stream, int num) { - return _writeNumber(stream, num); + return internal::writeNumber(stream, num); } const dump &operator<<(const dump &stream, unsigned int num) { - return _writeNumber(stream, num); + return internal::writeNumber(stream, num); } const dump &operator<<(const dump &stream, unsigned long num) { - return _writeNumber(stream, num); + return internal::writeNumber(stream, num); } const dump &operator<<(const dump &stream, unsigned long long num) { - return _writeNumber(stream, num); + return internal::writeNumber(stream, num); } const dump &operator<<(const dump &stream, double num) { if (num < 0) { - _writeChar('-'); + internal::writeChar('-'); num = -num; } - _writeNumber(stream, uint64(floor(num))); - _writeChar('.'); + internal::writeNumber(stream, uint64(floor(num))); + internal::writeChar('.'); num -= floor(num); for (int i = 0; i < 4; ++i) { num *= 10; int digit = int(floor(num)); - _writeChar('0' + digit); + internal::writeChar('0' + digit); num -= digit; } return stream; } - Qt::HANDLE LoggingCrashThreadId = 0; - bool LoggingCrashHeaderWritten = false; - QMutex LoggingCrashMutex; +namespace internal { - const char *BreakpadDumpPath = 0; - const wchar_t *BreakpadDumpPathW = 0; + Qt::HANDLE ReportingThreadId = nullptr; + bool ReportingHeaderWritten = false; + QMutex ReportingMutex; + + const char *BreakpadDumpPath = nullptr; + const wchar_t *BreakpadDumpPathW = nullptr; #if defined Q_OS_MAC || defined Q_OS_LINUX32 || defined Q_OS_LINUX64 struct sigaction SIG_def[32]; @@ -753,14 +761,34 @@ namespace SignalHandlers { } Qt::HANDLE thread = QThread::currentThreadId(); - if (thread == LoggingCrashThreadId) return; + if (thread == ReportingThreadId) return; - QMutexLocker lock(&LoggingCrashMutex); - LoggingCrashThreadId = thread; + QMutexLocker lock(&ReportingMutex); + ReportingThreadId = thread; - if (!LoggingCrashHeaderWritten) { - LoggingCrashHeaderWritten = true; - const AnnotationsMap c_ProcessAnnotations(ProcessAnnotations); + if (!ReportingHeaderWritten) { + ReportingHeaderWritten = true; + auto dec2hex = [](int value) -> char { + if (value >= 0 && value < 10) { + return '0' + value; + } else if (value >= 10 && value < 16) { + return 'a' + (value - 10); + } + return '#'; + }; + + for (const auto &i : ProcessAnnotationRefs) { + QByteArray utf8 = i.second->toUtf8(); + std::string wrapped; + wrapped.reserve(4 * utf8.size()); + for (auto ch : utf8) { + auto uch = static_cast(ch); + wrapped.append("\\x", 2).append(1, dec2hex(uch >> 4)).append(1, dec2hex(uch & 0x0F)); + } + ProcessAnnotations[i.first] = wrapped; + } + + const Annotations c_ProcessAnnotations(ProcessAnnotations); for (const auto &i : c_ProcessAnnotations) { dump() << i.first.c_str() << ": " << i.second.c_str() << "\n"; } @@ -843,7 +871,7 @@ namespace SignalHandlers { dump() << "\nBacktrace:\n"; - backtrace_symbols_fd(addresses, size, CrashDumpFileNo); + backtrace_symbols_fd(addresses, size, ReportFileNo); #else // Q_OS_MAC || Q_OS_LINUX32 || Q_OS_LINUX64 dump() << "\nBacktrace:\n"; @@ -853,7 +881,7 @@ namespace SignalHandlers { dump() << "\n"; - LoggingCrashThreadId = 0; + ReportingThreadId = nullptr; } bool SetSignalHandlers = true; @@ -890,8 +918,12 @@ namespace SignalHandlers { #endif // !TDESKTOP_DISABLE_CRASH_REPORTS +} // namespace internal + void StartCrashHandler() { #ifndef TDESKTOP_DISABLE_CRASH_REPORTS + using internal::ProcessAnnotations; + ProcessAnnotations["Binary"] = cExeName().toUtf8().constData(); ProcessAnnotations["ApiId"] = QString::number(ApiId).toUtf8().constData(); ProcessAnnotations["Version"] = (cBetaVersion() ? qsl("%1 beta").arg(cBetaVersion()) : (cDevVersion() ? qsl("%1 dev") : qsl("%1")).arg(AppVersion)).toUtf8().constData(); @@ -903,10 +935,10 @@ namespace SignalHandlers { QDir().mkpath(dumpspath); #ifdef Q_OS_WIN - BreakpadExceptionHandler = new google_breakpad::ExceptionHandler( + internal::BreakpadExceptionHandler = new google_breakpad::ExceptionHandler( dumpspath.toStdWString(), /*FilterCallback*/ 0, - DumpCallback, + internal::DumpCallback, /*context*/ 0, true ); @@ -914,16 +946,16 @@ namespace SignalHandlers { #ifdef MAC_USE_BREAKPAD #ifndef _DEBUG - BreakpadExceptionHandler = new google_breakpad::ExceptionHandler( + internal::BreakpadExceptionHandler = new google_breakpad::ExceptionHandler( QFile::encodeName(dumpspath).toStdString(), /*FilterCallback*/ 0, - DumpCallback, + internal::DumpCallback, /*context*/ 0, true, 0 ); #endif // !_DEBUG - SetSignalHandlers = false; + internal::SetSignalHandlers = false; #else // MAC_USE_BREAKPAD crashpad::CrashpadClient crashpad_client; std::string handler = (cExeDir() + cExeName() + qsl("/Contents/Helpers/crashpad_handler")).toUtf8().constData(); @@ -938,10 +970,10 @@ namespace SignalHandlers { } #endif // else for MAC_USE_BREAKPAD #elif defined Q_OS_LINUX64 || defined Q_OS_LINUX32 - BreakpadExceptionHandler = new google_breakpad::ExceptionHandler( + internal::BreakpadExceptionHandler = new google_breakpad::ExceptionHandler( google_breakpad::MinidumpDescriptor(QFile::encodeName(dumpspath).toStdString()), /*FilterCallback*/ 0, - DumpCallback, + internal::DumpCallback, /*context*/ 0, true, -1 @@ -954,9 +986,8 @@ namespace SignalHandlers { #ifndef TDESKTOP_DISABLE_CRASH_REPORTS #if !defined Q_OS_MAC || defined MAC_USE_BREAKPAD - if (BreakpadExceptionHandler) { - google_breakpad::ExceptionHandler *h = BreakpadExceptionHandler; - BreakpadExceptionHandler = 0; + if (internal::BreakpadExceptionHandler) { + google_breakpad::ExceptionHandler *h = getPointerAndReset(internal::BreakpadExceptionHandler); delete h; } #endif // !Q_OS_MAC || MAC_USE_BREAKPAD @@ -966,15 +997,16 @@ namespace SignalHandlers { Status start() { #ifndef TDESKTOP_DISABLE_CRASH_REPORTS - CrashDumpPath = cWorkingDir() + qsl("tdata/working"); + using internal::ReportPath; + ReportPath = cWorkingDir() + qsl("tdata/working"); #ifdef Q_OS_WIN FILE *f = nullptr; - if (_wfopen_s(&f, CrashDumpPath.toStdWString().c_str(), L"rb") != 0) { + if (_wfopen_s(&f, ReportPath.toStdWString().c_str(), L"rb") != 0) { f = nullptr; } else { #else // !Q_OS_WIN - if (FILE *f = fopen(QFile::encodeName(CrashDumpPath).constData(), "rb")) { + if (FILE *f = fopen(QFile::encodeName(ReportPath).constData(), "rb")) { #endif // else for !Q_OS_WIN QByteArray lastdump; char buffer[256 * 1024] = { 0 }; @@ -986,7 +1018,7 @@ namespace SignalHandlers { Sandbox::SetLastCrashDump(lastdump); - LOG(("Opened '%1' for reading, the previous Telegram Desktop launch was not finished properly :( Crash log size: %2").arg(CrashDumpPath).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; } @@ -997,48 +1029,48 @@ namespace SignalHandlers { Status restart() { #ifndef TDESKTOP_DISABLE_CRASH_REPORTS - if (CrashDumpFile) { + if (internal::ReportFile) { return Started; } #ifdef Q_OS_WIN - if (_wfopen_s(&CrashDumpFile, CrashDumpPath.toStdWString().c_str(), L"wb") != 0) { - CrashDumpFile = nullptr; + if (_wfopen_s(&internal::ReportFile, internal::ReportPath.toStdWString().c_str(), L"wb") != 0) { + internal::ReportFile = nullptr; } #else // Q_OS_WIN - CrashDumpFile = fopen(QFile::encodeName(CrashDumpPath).constData(), "wb"); + internal::ReportFile = fopen(QFile::encodeName(internal::ReportPath).constData(), "wb"); #endif // else for Q_OS_WIN - if (CrashDumpFile) { + if (internal::ReportFile) { #ifdef Q_OS_WIN - CrashDumpFileNo = _fileno(CrashDumpFile); + internal::ReportFileNo = _fileno(internal::ReportFile); #else // Q_OS_WIN - CrashDumpFileNo = fileno(CrashDumpFile); + internal::ReportFileNo = fileno(internal::ReportFile); #endif // else for Q_OS_WIN - if (SetSignalHandlers) { + if (internal::SetSignalHandlers) { #ifndef Q_OS_WIN struct sigaction sigact; - sigact.sa_sigaction = SignalHandlers::Handler; + sigact.sa_sigaction = SignalHandlers::internal::Handler; sigemptyset(&sigact.sa_mask); sigact.sa_flags = SA_NODEFER | SA_RESETHAND | SA_SIGINFO; - sigaction(SIGABRT, &sigact, &SIG_def[SIGABRT]); - sigaction(SIGSEGV, &sigact, &SIG_def[SIGSEGV]); - sigaction(SIGILL, &sigact, &SIG_def[SIGILL]); - sigaction(SIGFPE, &sigact, &SIG_def[SIGFPE]); - sigaction(SIGBUS, &sigact, &SIG_def[SIGBUS]); - sigaction(SIGSYS, &sigact, &SIG_def[SIGSYS]); + sigaction(SIGABRT, &sigact, &internal::SIG_def[SIGABRT]); + sigaction(SIGSEGV, &sigact, &internal::SIG_def[SIGSEGV]); + sigaction(SIGILL, &sigact, &internal::SIG_def[SIGILL]); + sigaction(SIGFPE, &sigact, &internal::SIG_def[SIGFPE]); + sigaction(SIGBUS, &sigact, &internal::SIG_def[SIGBUS]); + sigaction(SIGSYS, &sigact, &internal::SIG_def[SIGSYS]); #else // !Q_OS_WIN - signal(SIGABRT, SignalHandlers::Handler); - signal(SIGSEGV, SignalHandlers::Handler); - signal(SIGILL, SignalHandlers::Handler); - signal(SIGFPE, SignalHandlers::Handler); + signal(SIGABRT, SignalHandlers::internal::Handler); + signal(SIGSEGV, SignalHandlers::internal::Handler); + signal(SIGILL, SignalHandlers::internal::Handler); + signal(SIGFPE, SignalHandlers::internal::Handler); #endif // else for !Q_OS_WIN } return Started; } - LOG(("FATAL: Could not open '%1' for writing!").arg(CrashDumpPath)); + LOG(("FATAL: Could not open '%1' for writing!").arg(internal::ReportPath)); return CantOpen; #else // !TDESKTOP_DISABLE_CRASH_REPORTS @@ -1049,29 +1081,33 @@ namespace SignalHandlers { void finish() { #ifndef TDESKTOP_DISABLE_CRASH_REPORTS FinishCrashHandler(); - if (CrashDumpFile) { - fclose(CrashDumpFile); - CrashDumpFile = nullptr; + if (internal::ReportFile) { + fclose(internal::ReportFile); + internal::ReportFile = nullptr; #ifdef Q_OS_WIN - _wunlink(CrashDumpPath.toStdWString().c_str()); + _wunlink(internal::ReportPath.toStdWString().c_str()); #else // Q_OS_WIN - unlink(CrashDumpPath.toUtf8().constData()); + unlink(internal::ReportPath.toUtf8().constData()); #endif // else for Q_OS_WIN } #endif // !TDESKTOP_DISABLE_CRASH_REPORTS } - void setSelfUsername(const QString &username) { - if (username.trimmed().isEmpty()) { - ProcessAnnotations.erase("Username"); + void setCrashAnnotation(const std::string &key, const QString &value) { + if (!value.trimmed().isEmpty()) { + internal::ProcessAnnotations[key] = value.toUtf8().constData(); } else { - ProcessAnnotations["Username"] = username.toUtf8().constData(); + internal::ProcessAnnotations.erase(key); } } - void setAssertionInfo(const QString &info) { - ProcessAnnotations["Assertion"] = info.toUtf8().constData(); + void setCrashAnnotationRef(const std::string &key, const QString *valuePtr) { + if (valuePtr) { + internal::ProcessAnnotationRefs[key] = valuePtr; + } else { + internal::ProcessAnnotationRefs.erase(key); + } } } diff --git a/Telegram/SourceFiles/logs.h b/Telegram/SourceFiles/logs.h index 6e997e4cf..737d6ecff 100644 --- a/Telegram/SourceFiles/logs.h +++ b/Telegram/SourceFiles/logs.h @@ -107,7 +107,13 @@ namespace SignalHandlers { Status restart(); // can be only CantOpen or Started void finish(); - void setSelfUsername(const QString &username); - void setAssertionInfo(const QString &info); + void setCrashAnnotation(const std::string &key, const QString &value); + + // Remembers value pointer and tries to add the value to the crash report. + // Attention! You should call clearCrashAnnotationRef(key) before destroying value. + void setCrashAnnotationRef(const std::string &key, const QString *valuePtr); + inline void clearCrashAnnotationRef(const std::string &key) { + setCrashAnnotationRef(key, nullptr); + } } diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index 921fe7f76..64ef184e8 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -2973,9 +2973,7 @@ void MainWidget::feedMessageIds(const MTPVector &updates) { } bool MainWidget::updateFail(const RPCError &e) { - if (MTP::authedId()) { - App::logOut(); - } + App::logOutDelayed(); return true; } @@ -3722,7 +3720,7 @@ bool MainWidget::inviteImportFail(const RPCError &error) { void MainWidget::startFull(const MTPVector &users) { const QVector &v(users.c_vector().v); if (v.isEmpty() || v[0].type() != mtpc_user || !v[0].c_user().is_self()) { // wtf?.. - return App::logOut(); + return App::logOutDelayed(); } start(v[0]); } diff --git a/Telegram/SourceFiles/stdafx.h b/Telegram/SourceFiles/stdafx.h index 12885f468..e87a6c5b0 100644 --- a/Telegram/SourceFiles/stdafx.h +++ b/Telegram/SourceFiles/stdafx.h @@ -25,6 +25,8 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #ifdef __cplusplus +#include + #include #include #include diff --git a/Telegram/SourceFiles/types.h b/Telegram/SourceFiles/types.h index a6a776a3e..67c39475c 100644 --- a/Telegram/SourceFiles/types.h +++ b/Telegram/SourceFiles/types.h @@ -294,12 +294,12 @@ void as_const(const T&&) = delete; #include "logs.h" -static volatile int *t_assert_nullptr = 0; +static volatile int *t_assert_nullptr = nullptr; inline void t_noop() {} inline void t_assert_fail(const char *message, const char *file, int32 line) { QString info(qsl("%1 %2:%3").arg(message).arg(file).arg(line)); LOG(("Assertion Failed! %1 %2:%3").arg(info)); - SignalHandlers::setAssertionInfo(info); + SignalHandlers::setCrashAnnotation("Assertion", info); *t_assert_nullptr = 0; } #define t_assert_full(condition, message, file, line) ((!(condition)) ? t_assert_fail(message, file, line) : t_noop()) @@ -646,20 +646,22 @@ MimeType mimeTypeForName(const QString &mime); MimeType mimeTypeForFile(const QFileInfo &file); MimeType mimeTypeForData(const QByteArray &data); -inline int32 rowscount(int32 count, int32 perrow) { - return (count + perrow - 1) / perrow; +#include + +inline int rowscount(int fullCount, int countPerRow) { + return (fullCount + countPerRow - 1) / countPerRow; } -inline int32 floorclamp(int32 value, int32 step, int32 lowest, int32 highest) { +inline int floorclamp(int value, int step, int lowest, int highest) { return qMin(qMax(value / step, lowest), highest); } -inline int32 floorclamp(float64 value, int32 step, int32 lowest, int32 highest) { - return qMin(qMax(qFloor(value / step), lowest), highest); +inline int floorclamp(float64 value, int step, int lowest, int highest) { + return qMin(qMax(static_cast(std::floor(value / step)), lowest), highest); } -inline int32 ceilclamp(int32 value, int32 step, int32 lowest, int32 highest) { - return qMax(qMin((value / step) + ((value % step) ? 1 : 0), highest), lowest); +inline int ceilclamp(int value, int step, int lowest, int highest) { + return qMax(qMin((value + step - 1) / step, highest), lowest); } -inline int32 ceilclamp(float64 value, int32 step, int32 lowest, int32 highest) { - return qMax(qMin(qCeil(value / step), highest), lowest); +inline int ceilclamp(float64 value, int32 step, int32 lowest, int32 highest) { + return qMax(qMin(static_cast(std::ceil(value / step)), highest), lowest); } enum ForwardWhatMessages { diff --git a/Telegram/SourceFiles/window.cpp b/Telegram/SourceFiles/window.cpp index 3299275fc..285766699 100644 --- a/Telegram/SourceFiles/window.cpp +++ b/Telegram/SourceFiles/window.cpp @@ -287,18 +287,20 @@ void NotifyWindow::startHiding() { void NotifyWindow::mousePressEvent(QMouseEvent *e) { if (!history) return; + PeerId peer = history->peer->id; + MsgId msgId = (!history->peer->isUser() && item && item->mentionsMe() && item->id > 0) ? item->id : ShowAtUnreadMsgId; if (e->button() == Qt::RightButton) { unlinkHistoryAndNotify(); - } else if (history) { + } else { App::wnd()->showFromTray(); if (App::passcoded()) { App::wnd()->setInnerFocus(); App::wnd()->notifyClear(); } else { App::wnd()->hideSettings(); - Ui::showPeerHistory(peer, (!history->peer->isUser() && item && item->mentionsMe() && item->id > 0) ? item->id : ShowAtUnreadMsgId); + Ui::showPeerHistory(peer, msgId); } e->ignore(); } @@ -505,11 +507,8 @@ void Window::clearWidgets() { settings = 0; } if (main) { - main->animStop_show(); - main->hide(); - main->deleteLater(); - main->rpcClear(); - main = 0; + delete main; + main = nullptr; } if (intro) { intro->stop_show(); @@ -691,7 +690,7 @@ void Window::setupMain(bool anim, const MTPUser *self) { } void Window::updateCounter() { - if (App::quitting()) return; + if (!Global::started() || App::quitting()) return; psUpdateCounter(); title->updateCounter(); @@ -1185,7 +1184,11 @@ void Window::onLogout() { } void Window::onLogoutSure() { - App::logOut(); + if (MTP::authedId()) { + App::logOut(); + } else { + setupIntro(true); + } } void Window::updateGlobalMenu() { @@ -1951,7 +1954,10 @@ PreLaunchWindow::PreLaunchWindow(QString title) : TWidget(0) { tmp.setText(qsl("Tmp")); _size = tmp.sizeHint().height(); - setStyleSheet(qsl("QPushButton { padding: %1px %2px; background-color: #ffffff; border-radius: %3px; }\nQPushButton#confirm:hover, QPushButton#cancel:hover { background-color: #edf7ff; color: #2f9fea; }\nQPushButton#confirm { color: #2f9fea; }\nQPushButton#cancel { color: #aeaeae; }\nQLineEdit { border: 1px solid #e0e0e0; padding: 5px; }\nQLineEdit:focus { border: 2px solid #62c0f7; padding: 4px; }").arg(qFloor(_size / 2)).arg(qFloor(_size)).arg(qFloor(_size / 5))); + int paddingVertical = (_size / 2); + int paddingHorizontal = _size; + int borderRadius = (_size / 5); + setStyleSheet(qsl("QPushButton { padding: %1px %2px; background-color: #ffffff; border-radius: %3px; }\nQPushButton#confirm:hover, QPushButton#cancel:hover { background-color: #edf7ff; color: #2f9fea; }\nQPushButton#confirm { color: #2f9fea; }\nQPushButton#cancel { color: #aeaeae; }\nQLineEdit { border: 1px solid #e0e0e0; padding: 5px; }\nQLineEdit:focus { border: 2px solid #62c0f7; padding: 4px; }").arg(paddingVertical).arg(paddingHorizontal).arg(borderRadius)); if (!PreLaunchWindowInstance) { PreLaunchWindowInstance = this; } diff --git a/Telegram/SourceFiles/window.h b/Telegram/SourceFiles/window.h index 0c7f589c0..2846560b5 100644 --- a/Telegram/SourceFiles/window.h +++ b/Telegram/SourceFiles/window.h @@ -363,7 +363,7 @@ public: PreLaunchWindow(QString title = QString()); void activate(); - float64 basicSize() const { + int basicSize() const { return _size; } ~PreLaunchWindow(); @@ -372,7 +372,7 @@ public: protected: - float64 _size; + int _size; }; diff --git a/Telegram/Telegram.plist b/Telegram/Telegram.plist index 8e055f9b7..d2af99bfb 100644 --- a/Telegram/Telegram.plist +++ b/Telegram/Telegram.plist @@ -11,7 +11,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 0.9.36 + 0.9.39 CFBundleSignature ???? CFBundleURLTypes diff --git a/Telegram/Telegram.rc b/Telegram/Telegram.rc index a6392a42a..f9be16de3 100644 --- a/Telegram/Telegram.rc +++ b/Telegram/Telegram.rc @@ -34,8 +34,8 @@ IDI_ICON1 ICON "SourceFiles\\art\\icon256.ico" // VS_VERSION_INFO VERSIONINFO - FILEVERSION 0,9,36,0 - PRODUCTVERSION 0,9,36,0 + FILEVERSION 0,9,39,0 + PRODUCTVERSION 0,9,39,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -51,10 +51,10 @@ BEGIN BLOCK "040904b0" BEGIN VALUE "CompanyName", "Telegram Messenger LLP" - VALUE "FileVersion", "0.9.36.0" + VALUE "FileVersion", "0.9.39.0" VALUE "LegalCopyright", "Copyright (C) 2014-2016" VALUE "ProductName", "Telegram Desktop" - VALUE "ProductVersion", "0.9.36.0" + VALUE "ProductVersion", "0.9.39.0" END END BLOCK "VarFileInfo" diff --git a/Telegram/Telegram.vcxproj b/Telegram/Telegram.vcxproj index f9ac63760..b2a77729b 100644 --- a/Telegram/Telegram.vcxproj +++ b/Telegram/Telegram.vcxproj @@ -123,6 +123,7 @@ true + /ignore:4099 %(AdditionalOptions) @@ -154,6 +155,7 @@ true + /ignore:4099 %(AdditionalOptions) diff --git a/Telegram/Telegram.xcodeproj/project.pbxproj b/Telegram/Telegram.xcodeproj/project.pbxproj index 7c99556fb..bed09ed1b 100644 --- a/Telegram/Telegram.xcodeproj/project.pbxproj +++ b/Telegram/Telegram.xcodeproj/project.pbxproj @@ -1772,7 +1772,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 0.9.36; + CURRENT_PROJECT_VERSION = 0.9.39; DEBUG_INFORMATION_FORMAT = dwarf; GCC_GENERATE_DEBUGGING_SYMBOLS = YES; GCC_OPTIMIZATION_LEVEL = 0; @@ -1791,7 +1791,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; COPY_PHASE_STRIP = YES; - CURRENT_PROJECT_VERSION = 0.9.36; + CURRENT_PROJECT_VERSION = 0.9.39; GCC_GENERATE_DEBUGGING_SYMBOLS = NO; GCC_OPTIMIZATION_LEVEL = fast; GCC_PREFIX_HEADER = ./SourceFiles/stdafx.h; @@ -1820,10 +1820,10 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = ""; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 0.9.36; + CURRENT_PROJECT_VERSION = 0.9.39; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DYLIB_COMPATIBILITY_VERSION = 0.9; - DYLIB_CURRENT_VERSION = 0.9.36; + DYLIB_CURRENT_VERSION = 0.9.39; ENABLE_STRICT_OBJC_MSGSEND = YES; FRAMEWORK_SEARCH_PATHS = ""; GCC_GENERATE_DEBUGGING_SYMBOLS = YES; @@ -1961,10 +1961,10 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = ""; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 0.9.36; + CURRENT_PROJECT_VERSION = 0.9.39; DEBUG_INFORMATION_FORMAT = dwarf; DYLIB_COMPATIBILITY_VERSION = 0.9; - DYLIB_CURRENT_VERSION = 0.9.36; + DYLIB_CURRENT_VERSION = 0.9.39; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; FRAMEWORK_SEARCH_PATHS = ""; diff --git a/Telegram/Version b/Telegram/Version index 2227962ec..355c48b4b 100644 --- a/Telegram/Version +++ b/Telegram/Version @@ -1,6 +1,6 @@ -AppVersion 9036 +AppVersion 9039 AppVersionStrMajor 0.9 -AppVersionStrSmall 0.9.36 -AppVersionStr 0.9.36 +AppVersionStrSmall 0.9.39 +AppVersionStr 0.9.39 DevChannel 1 BetaVersion 0 9034004 diff --git a/Telegram/build/vc/codegen_style/codegen_style.vcxproj b/Telegram/build/vc/codegen_style/codegen_style.vcxproj new file mode 100644 index 000000000..cfff29554 --- /dev/null +++ b/Telegram/build/vc/codegen_style/codegen_style.vcxproj @@ -0,0 +1,91 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + + + + {E4DF8176-4DEF-4859-962F-B497E3E7A323} + Qt4VSv1.0 + 8.1 + + + + Application + v140 + + + Application + v140 + + + + + + + + + + + + + <_ProjectFileVersion>14.0.24730.2 + + + $(SolutionDir)$(Platform)\codegen\$(Configuration)\ + $(SolutionDir)$(Platform)\obj\$(ProjectName)\ + + + $(SolutionDir)$(Platform)\$(Configuration)\ + + + + UNICODE;WIN32;QT_CORE_LIB;%(PreprocessorDefinitions) + Disabled + ProgramDatabase + MultiThreadedDebug + .;$(QTDIR)\include;.\GeneratedFiles\$(ConfigurationName);$(QTDIR)\include\QtCore;%(AdditionalIncludeDirectories) + true + + + Console + $(OutDir)\$(ProjectName).exe + $(QTDIR)\lib;$(QTDIR)\plugins;%(AdditionalLibraryDirectories) + true + ws2_32.lib;qtmaind.lib;qtharfbuzzngd.lib;qtpcred.lib;qtfreetyped.lib;imageformats\qwebpd.lib;Qt5Cored.lib;%(AdditionalDependencies) + + + + + UNICODE;WIN32;QT_NO_DEBUG;NDEBUG;QT_CORE_LIB;%(PreprocessorDefinitions) + + MultiThreadedDLL + .;$(QTDIR)\include;.\GeneratedFiles\$(ConfigurationName);$(QTDIR)\include\QtCore;%(AdditionalIncludeDirectories) + true + + + Console + $(OutDir)\$(ProjectName).exe + $(QTDIR)\lib;%(AdditionalLibraryDirectories) + false + qtmain.lib;Qt5Core.lib;%(AdditionalDependencies) + + + + + + + + + + + \ No newline at end of file diff --git a/Telegram/build/vc/codegen_style/codegen_style.vcxproj.filters b/Telegram/build/vc/codegen_style/codegen_style.vcxproj.filters new file mode 100644 index 000000000..3263d5640 --- /dev/null +++ b/Telegram/build/vc/codegen_style/codegen_style.vcxproj.filters @@ -0,0 +1,28 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;cxx;c;def + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h + + + {D9D6E242-F8AF-46E4-B9FD-80ECBC20BA3E} + qrc;* + false + + + {71ED8ED8-ACB9-4CE9-BBE1-E00B30144E11} + moc;h;cpp + False + + + + + Source Files + + + \ No newline at end of file