Merged with master.

This commit is contained in:
John Preston 2016-04-01 12:54:32 +04:00
commit fa4137418a
35 changed files with 771 additions and 396 deletions

1
.gitignore vendored
View file

@ -7,6 +7,7 @@
/Telegram/SourceFiles/art/sprite_125x.png /Telegram/SourceFiles/art/sprite_125x.png
/Telegram/SourceFiles/art/sprite_150x.png /Telegram/SourceFiles/art/sprite_150x.png
/Telegram/*.user /Telegram/*.user
*.vcxproj.user
*.suo *.suo
*.sdf *.sdf
*.opensdf *.opensdf

View file

@ -39,5 +39,9 @@ arch:
- libtool --finish /usr/lib - libtool --finish /usr/lib
- .travis/build.sh - .travis/build.sh
before_install:
- "export TRAVIS_COMMIT_MSG=\"$(git log --format=%B --no-merges -n 1)\""
- .travis/check.sh
script: script:
- .travis/arch.sh - .travis/arch.sh

View file

@ -10,23 +10,6 @@ run() {
check 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() { downloadLibs() {
travis_fold_start "download_libs" travis_fold_start "download_libs"
# Move telegram project to subfolder # Move telegram project to subfolder
@ -172,28 +155,6 @@ check() {
fi fi
} }
start_msg() { source ./.travis/common.sh
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:$*"
}
run run

25
.travis/check.sh Executable file
View file

@ -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

40
.travis/common.sh Executable file
View file

@ -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:$*"
}

View file

@ -1,7 +1,7 @@
 
Microsoft Visual Studio Solution File, Format Version 12.00 Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2013 # Visual Studio 14
VisualStudioVersion = 12.0.30501.0 VisualStudioVersion = 14.0.24720.0
MinimumVisualStudioVersion = 10.0.40219.1 MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Telegram", "Telegram\Telegram.vcxproj", "{B12702AD-ABFB-343A-A199-8E24837244A3}" Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Telegram", "Telegram\Telegram.vcxproj", "{B12702AD-ABFB-343A-A199-8E24837244A3}"
ProjectSection(ProjectDependencies) = postProject ProjectSection(ProjectDependencies) = postProject
@ -18,10 +18,12 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Updater", "Telegram\Updater
EndProject EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MetaLang", "Telegram\MetaLang.vcxproj", "{E417CAA4-259B-4C99-88E3-805F1300E8EB}" Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MetaLang", "Telegram\MetaLang.vcxproj", "{E417CAA4-259B-4C99-88E3-805F1300E8EB}"
EndProject 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 EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Packer", "Telegram\Packer.vcxproj", "{56A9A4B2-21E5-4360-AFA8-85B43AC43B08}" Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Packer", "Telegram\Packer.vcxproj", "{56A9A4B2-21E5-4360-AFA8-85B43AC43B08}"
EndProject EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "codegen_style", "Telegram\build\vc\codegen_style\codegen_style.vcxproj", "{E4DF8176-4DEF-4859-962F-B497E3E7A323}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32 Debug|Win32 = Debug|Win32
@ -82,8 +84,21 @@ Global
{56A9A4B2-21E5-4360-AFA8-85B43AC43B08}.Deploy|x64.ActiveCfg = Release|Win32 {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|Win32.ActiveCfg = Release|Win32
{56A9A4B2-21E5-4360-AFA8-85B43AC43B08}.Release|x64.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 EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
EndGlobalSection EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{E4DF8176-4DEF-4859-962F-B497E3E7A323} = {2F863EAD-33C9-4014-A573-93F085BA9CB1}
EndGlobalSection
EndGlobal EndGlobal

View file

@ -12,7 +12,7 @@ CONFIG(release, debug|release) {
DESTDIR = ./../ReleaseLang DESTDIR = ./../ReleaseLang
} }
CONFIG += plugin static CONFIG += plugin static c++11
macx { macx {
QMAKE_INFO_PLIST = ./SourceFiles/_other/Lang.plist QMAKE_INFO_PLIST = ./SourceFiles/_other/Lang.plist

View file

@ -12,7 +12,7 @@ CONFIG(release, debug|release) {
DESTDIR = ./../ReleaseStyle DESTDIR = ./../ReleaseStyle
} }
CONFIG += plugin static CONFIG += plugin static c++11
macx { macx {
QMAKE_INFO_PLIST = ./SourceFiles/_other/Style.plist QMAKE_INFO_PLIST = ./SourceFiles/_other/Style.plist

View file

@ -1052,8 +1052,8 @@ msgMinWidth: 190px;
msgPhotoSize: 33px; msgPhotoSize: 33px;
msgPhotoSkip: 40px; msgPhotoSkip: 40px;
msgPadding: margins(13px, 7px, 13px, 8px); msgPadding: margins(13px, 7px, 13px, 8px);
msgMargin: margins(13px, 6px, 53px, 2px); msgMargin: margins(13px, 10px, 53px, 2px);
msgMarginTopAttached: 2px; msgMarginTopAttached: 3px;
msgLnkPadding: 2px; // for media open / save links msgLnkPadding: 2px; // for media open / save links
msgBorder: #f0f0f0; msgBorder: #f0f0f0;
msgInBg: #fff; msgInBg: #fff;
@ -1105,7 +1105,7 @@ msgServiceBg: #89a0b47f;
msgServiceSelectBg: #bbc8d4a2; msgServiceSelectBg: #bbc8d4a2;
msgServiceColor: #FFF; msgServiceColor: #FFF;
msgServicePadding: margins(12px, 3px, 12px, 4px); msgServicePadding: margins(12px, 3px, 12px, 4px);
msgServiceMargin: margins(10px, 9px, 80px, 5px); msgServiceMargin: margins(10px, 10px, 80px, 2px);
msgColor: #000; msgColor: #000;
msgDateColor: #000; msgDateColor: #000;
@ -1543,6 +1543,7 @@ reportSpamBg: #fffffff0;
newMsgSound: ':/gui/art/newmsg.wav'; newMsgSound: ':/gui/art/newmsg.wav';
unreadBarHeight: 32px; unreadBarHeight: 32px;
unreadBarMargin: 8px;
unreadBarFont: semiboldFont; unreadBarFont: semiboldFont;
unreadBarBG: #fcfbfa; unreadBarBG: #fcfbfa;
unreadBarBorder: shadowColor; unreadBarBorder: shadowColor;

View file

@ -174,21 +174,19 @@ namespace App {
return main() ? main()->api() : 0; return main() ? main()->api() : 0;
} }
namespace {
bool loggedOut() { bool loggedOut() {
Window *w(wnd());
if (cHasPasscode()) { if (cHasPasscode()) {
cSetHasPasscode(false); cSetHasPasscode(false);
} }
if (audioPlayer()) { if (audioPlayer()) {
audioPlayer()->stopAndClear(); audioPlayer()->stopAndClear();
} }
if (w) { if (Window *w = wnd()) {
w->tempDirDelete(Local::ClearManagerAll); w->tempDirDelete(Local::ClearManagerAll);
w->notifyClearFast(); w->notifyClearFast();
w->setupIntro(true); w->setupIntro(true);
} }
MainWidget *m(main());
if (m) m->destroyData();
MTP::authed(0); MTP::authed(0);
Local::reset(); Local::reset();
@ -199,13 +197,14 @@ namespace App {
globalNotifyChatsPtr = UnknownNotifySettings; globalNotifyChatsPtr = UnknownNotifySettings;
if (App::uploader()) App::uploader()->clear(); if (App::uploader()) App::uploader()->clear();
clearStorageImages(); clearStorageImages();
if (w) { if (Window *w = wnd()) {
w->getTitle()->updateBackButton(); w->getTitle()->updateBackButton();
w->updateTitleStatus(); w->updateTitleStatus();
w->getTitle()->resizeEvent(0); w->getTitle()->resizeEvent(0);
} }
return true; return true;
} }
} // namespace
void logOut() { void logOut() {
if (MTP::started()) { 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 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)); 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 // see also Local::readPeer
QString pname = (showPhoneChanged || phoneChanged || nameChanged) ? ((showPhone && !phone.isEmpty()) ? formatPhone(phone) : QString()) : data->nameOrPhone; QString pname = (showPhoneChanged || phoneChanged || nameChanged) ? ((showPhone && !phone.isEmpty()) ? formatPhone(phone) : QString()) : data->nameOrPhone;
if (!minimal && d.is_self() && uname != data->username) { if (!minimal && d.is_self() && uname != data->username) {
SignalHandlers::setSelfUsername(uname); SignalHandlers::setCrashAnnotation("Username", uname);
} }
data->setName(fname, lname, pname, uname); data->setName(fname, lname, pname, uname);
if (d.has_photo()) { if (d.has_photo()) {
@ -1444,12 +1447,12 @@ namespace App {
PeerData *peerByName(const QString &username) { PeerData *peerByName(const QString &username) {
QString uname(username.trimmed()); QString uname(username.trimmed());
for (PeersData::const_iterator i = peersData.cbegin(), e = peersData.cend(); i != e; ++i) { for_const (PeerData *peer, peersData) {
if (!i.value()->userName().compare(uname, Qt::CaseInsensitive)) { if (!peer->userName().compare(uname, Qt::CaseInsensitive)) {
return i.value(); return peer;
} }
} }
return 0; return nullptr;
} }
void updateImage(ImagePtr &old, ImagePtr now) { void updateImage(ImagePtr &old, ImagePtr now) {
@ -1855,20 +1858,20 @@ namespace App {
cSetSavedPeers(SavedPeers()); cSetSavedPeers(SavedPeers());
cSetSavedPeersByTime(SavedPeersByTime()); cSetSavedPeersByTime(SavedPeersByTime());
cSetRecentInlineBots(RecentInlineBots()); cSetRecentInlineBots(RecentInlineBots());
for (PeersData::const_iterator i = peersData.cbegin(), e = peersData.cend(); i != e; ++i) { for_const (PeerData *peer, peersData) {
delete *i; delete peer;
} }
peersData.clear(); peersData.clear();
for (PhotosData::const_iterator i = ::photosData.cbegin(), e = ::photosData.cend(); i != e; ++i) { for_const (PhotoData *photo, ::photosData) {
delete *i; delete photo;
} }
::photosData.clear(); ::photosData.clear();
for (DocumentsData::const_iterator i = ::documentsData.cbegin(), e = ::documentsData.cend(); i != e; ++i) { for_const (DocumentData *document, ::documentsData) {
delete *i; delete document;
} }
::documentsData.clear(); ::documentsData.clear();
for (WebPagesData::const_iterator i = webPagesData.cbegin(), e = webPagesData.cend(); i != e; ++i) { for_const (WebPageData *webpage, webPagesData) {
delete *i; delete webpage;
} }
webPagesData.clear(); webPagesData.clear();
if (api()) api()->clearWebPageRequests(); if (api()) api()->clearWebPageRequests();

View file

@ -56,7 +56,6 @@ namespace App {
ApiWrap *api(); ApiWrap *api();
void logOut(); void logOut();
bool loggedOut();
QString formatPhone(QString phone); QString formatPhone(QString phone);

View file

@ -0,0 +1,3 @@
int main(int argc, char *argv[]) {
return 0;
}

View file

@ -20,8 +20,8 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/ */
#pragma once #pragma once
static const int32 AppVersion = 9036; static const int32 AppVersion = 9039;
static const wchar_t *AppVersionStr = L"0.9.36"; static const wchar_t *AppVersionStr = L"0.9.39";
static const bool DevVersion = true; static const bool DevVersion = true;
//#define BETA_VERSION (9034004ULL) // just comment this line to build public version //#define BETA_VERSION (9034004ULL) // just comment this line to build public version

View file

@ -941,6 +941,8 @@ void EmojiPanInner::selectEmoji(EmojiPtr emoji) {
} }
void EmojiPanInner::onShowPicker() { void EmojiPanInner::onShowPicker() {
if (_pickerSel < 0) return;
int tab = (_pickerSel / MatrixRowShift), sel = _pickerSel % MatrixRowShift; int tab = (_pickerSel / MatrixRowShift), sel = _pickerSel % MatrixRowShift;
if (tab < emojiTabCount && sel < _emojis[tab].size() && _emojis[tab][sel]->color) { if (tab < emojiTabCount && sel < _emojis[tab].size() && _emojis[tab][sel]->color) {
int32 y = 0; int32 y = 0;

View file

@ -120,6 +120,12 @@ namespace App {
} }
} }
void logOutDelayed() {
if (Window *w = App::wnd()) {
QMetaObject::invokeMethod(w, "onLogoutSure", Qt::QueuedConnection);
}
}
} }
namespace Ui { namespace Ui {

View file

@ -38,6 +38,9 @@ namespace App {
void showSettings(); void showSettings();
void activateClickHandler(ClickHandlerPtr handler, Qt::MouseButton button); void activateClickHandler(ClickHandlerPtr handler, Qt::MouseButton button);
void logOutDelayed();
}; };
namespace Ui { namespace Ui {

View file

@ -3572,7 +3572,14 @@ TextBlock::TextBlock(const style::font &font, const QString &str, QFixed minResi
layout.beginLayout(); layout.beginLayout();
layout.createLine(); layout.createLine();
bool logCrashString = (rand_value<uchar>() % 4 == 1);
if (logCrashString) {
SignalHandlers::setCrashAnnotationRef("CrashString", &part);
}
BlockParser parser(&engine, this, minResizeWidth, _from, part); BlockParser parser(&engine, this, minResizeWidth, _from, part);
if (logCrashString) {
SignalHandlers::clearCrashAnnotationRef("CrashString");
}
layout.endLayout(); layout.endLayout();
} }

View file

@ -377,11 +377,13 @@ bool History::updateTyping(uint64 ms, bool force) {
return changed; return changed;
} }
ChannelHistory::ChannelHistory(const PeerId &peer) : History(peer), ChannelHistory::ChannelHistory(const PeerId &peer) : History(peer)
unreadCountAll(0), , unreadCountAll(0)
_onlyImportant(!isMegagroup()), , _onlyImportant(!isMegagroup())
_otherOldLoaded(false), _otherNewLoaded(true), , _otherOldLoaded(false)
_collapseMessage(0), _joinedMessage(0) { , _otherNewLoaded(true)
, _collapseMessage(nullptr)
, _joinedMessage(nullptr) {
} }
bool ChannelHistory::isSwitchReadyFor(MsgId switchId, MsgId &fixInScrollMsgId, int32 &fixInScrollMsgTop) { bool ChannelHistory::isSwitchReadyFor(MsgId switchId, MsgId &fixInScrollMsgId, int32 &fixInScrollMsgTop) {
@ -575,14 +577,8 @@ void ChannelHistory::addNewGroup(const MTPMessageGroup &group) {
if (onlyImportant()) { if (onlyImportant()) {
if (newLoaded) { if (newLoaded) {
HistoryBlock *block = blocks.isEmpty() ? pushBackNewBlock() : blocks.back(); t_assert(!isBuildingFrontBlock());
HistoryItem *prev = block->items.isEmpty() ? nullptr : block->items.back(); addMessageGroup(d);
prev = addMessageGroupAfterPrevToBlock(d, prev, block);
if (block->items.isEmpty()) {
blocks.pop_back();
delete block;
}
} }
} else { } else {
setNotLoadedAtBottom(); setNotLoadedAtBottom();
@ -639,14 +635,12 @@ HistoryJoined *ChannelHistory::insertJoinedMessage(bool unread) {
} }
} }
// adding new item to new block startBuildingFrontBlock();
HistoryBlock *block = pushFrontNewBlock();
_joinedMessage = HistoryJoined::create(this, inviteDate, inviter, flags); _joinedMessage = HistoryJoined::create(this, inviteDate, inviter, flags);
addItemToBlock(_joinedMessage, block); addItemToBlock(_joinedMessage);
t_assert(blocks.size() > 1); finishBuildingFrontBlock();
blocks.at(1)->items.front()->previousItemChanged();
return _joinedMessage; return _joinedMessage;
} }
@ -755,15 +749,15 @@ HistoryItem *ChannelHistory::addNewToBlocks(const MTPMessage &msg, NewMessageTyp
} }
if (!isImportant && onlyImportant()) { 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<HistoryGroup*>(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; return item;
} }
@ -819,22 +813,15 @@ void ChannelHistory::switchMode() {
clear(true); clear(true);
t_assert(!isBuildingFrontBlock());
newLoaded = _otherNewLoaded; newLoaded = _otherNewLoaded;
oldLoaded = _otherOldLoaded; oldLoaded = _otherOldLoaded;
if (int count = _otherList.size()) { if (int count = _otherList.size()) {
blocks.reserve(qCeil(count / float64(MessagesPerPage))); blocks.reserve((count / MessagesPerPage) + 1);
for (int i = 0; i < count; ++i) {
for (int i = 0; i < count;) { t_assert(_otherList.at(i)->detached());
HistoryBlock *block = pushBackNewBlock(); addItemToBlock(_otherList.at(i));
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());
} }
} }
@ -1138,6 +1125,8 @@ void Histories::clear() {
for (Map::const_iterator i = map.cbegin(), e = map.cend(); i != e; ++i) { for (Map::const_iterator i = map.cbegin(), e = map.cend(); i != e; ++i) {
delete i.value(); delete i.value();
} }
Global::RefPendingRepaintItems().clear();
_unreadFull = _unreadMuted = 0; _unreadFull = _unreadMuted = 0;
if (App::wnd()) { if (App::wnd()) {
App::wnd()->updateCounter(); App::wnd()->updateCounter();
@ -1545,16 +1534,10 @@ void History::eraseFromOverview(MediaOverviewType type, MsgId msgId) {
} }
HistoryItem *History::addNewItem(HistoryItem *adding, bool newMsg) { HistoryItem *History::addNewItem(HistoryItem *adding, bool newMsg) {
t_assert(adding != nullptr); t_assert(!isBuildingFrontBlock());
t_assert(adding->detached()); addItemToBlock(adding);
HistoryBlock *block = blocks.isEmpty() ? pushBackNewBlock() : blocks.back();
adding->attachToBlock(block, block->items.size());
block->items.push_back(adding);
adding->previousItemChanged();
setLastMessage(adding); setLastMessage(adding);
if (newMsg) { if (newMsg) {
newItemAdded(adding); 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()); item->attachToBlock(block, block->items.size());
block->items.push_back(item); block->items.push_back(item);
item->previousItemChanged(); item->previousItemChanged();
return item;
}
HistoryItem *History::addMessageGroupAfterPrevToBlock(const MTPDmessageGroup &group, HistoryItem *prev, HistoryBlock *block) { if (isBuildingFrontBlock() && _buildingFrontBlock->expectedItemsCount > 0) {
if (prev && prev->type() == HistoryItemGroup) { --_buildingFrontBlock->expectedItemsCount;
static_cast<HistoryGroup*>(prev)->uniteWith(group.vmin_id.v, group.vmax_id.v, group.vcount.v);
return prev;
} }
return addItemToBlock(HistoryGroup::create(this, group, prev ? prev->date : date(group.vdate)), block);
} }
void History::addOlderSlice(const QVector<MTPMessage> &slice, const QVector<MTPMessageGroup> *collapsed) { void History::addOlderSlice(const QVector<MTPMessage> &slice, const QVector<MTPMessageGroup> *collapsed) {
@ -1695,10 +1709,8 @@ void History::addOlderSlice(const QVector<MTPMessage> &slice, const QVector<MTPM
const MTPMessageGroup *groupsBegin = (isChannel() && collapsed) ? collapsed->constData() : 0, *groupsIt = groupsBegin, *groupsEnd = (isChannel() && collapsed) ? (groupsBegin + collapsed->size()) : 0; const MTPMessageGroup *groupsBegin = (isChannel() && collapsed) ? collapsed->constData() : 0, *groupsIt = groupsBegin, *groupsEnd = (isChannel() && collapsed) ? (groupsBegin + collapsed->size()) : 0;
HistoryItem *prev = nullptr; startBuildingFrontBlock(slice.size() + (collapsed ? collapsed->size() : 0));
HistoryBlock *block = pushFrontNewBlock();
block->items.reserve(slice.size() + (collapsed ? collapsed->size() : 0));
for (auto i = slice.cend(), e = slice.cbegin(); i != e;) { for (auto i = slice.cend(), e = slice.cbegin(); i != e;) {
--i; --i;
HistoryItem *adding = createItem(*i, false, true); HistoryItem *adding = createItem(*i, false, true);
@ -1709,23 +1721,21 @@ void History::addOlderSlice(const QVector<MTPMessage> &slice, const QVector<MTPM
const MTPDmessageGroup &group(groupsIt->c_messageGroup()); const MTPDmessageGroup &group(groupsIt->c_messageGroup());
if (group.vmin_id.v >= adding->id) break; 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) { for (; groupsIt != groupsEnd; ++groupsIt) {
if (groupsIt->type() != mtpc_messageGroup) continue; if (groupsIt->type() != mtpc_messageGroup) continue;
const MTPDmessageGroup &group(groupsIt->c_messageGroup()); const MTPDmessageGroup &group(groupsIt->c_messageGroup());
prev = addMessageGroupAfterPrevToBlock(group, prev, block); addMessageGroup(group);
} }
if (block->items.isEmpty()) { HistoryBlock *block = finishBuildingFrontBlock();
blocks.pop_front(); if (!block) {
delete block; // If no items were added it means we've loaded everything old.
block = nullptr;
oldLoaded = true; oldLoaded = true;
} else if (loadedAtBottom()) { // add photos to overview and authors to lastAuthors / lastParticipants } else if (loadedAtBottom()) { // add photos to overview and authors to lastAuthors / lastParticipants
bool channel = isChannel(); bool channel = isChannel();
@ -1803,28 +1813,6 @@ void History::addOlderSlice(const QVector<MTPMessage> &slice, const QVector<MTPM
} }
} }
// some checks if there was some message history already
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<HistoryGroup*>(first)->uniteWith(static_cast<HistoryGroup*>(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()) { if (isChannel()) {
asChannelHistory()->checkJoinedMessage(); asChannelHistory()->checkJoinedMessage();
asChannelHistory()->checkMaxReadMessageDate(); asChannelHistory()->checkMaxReadMessageDate();
@ -1840,14 +1828,11 @@ void History::addNewerSlice(const QVector<MTPMessage> &slice, const QVector<MTPM
if (!lastMsg) setLastMessage(lastImportantMessage()); if (!lastMsg) setLastMessage(lastImportantMessage());
} }
t_assert(!isBuildingFrontBlock());
if (!slice.isEmpty() || (isChannel() && collapsed && !collapsed->isEmpty())) { if (!slice.isEmpty() || (isChannel() && collapsed && !collapsed->isEmpty())) {
const MTPMessageGroup *groupsBegin = (isChannel() && collapsed) ? collapsed->constData() : 0, *groupsIt = groupsBegin, *groupsEnd = (isChannel() && collapsed) ? (groupsBegin + collapsed->size()) : 0; 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(); bool atLeastOneAdded = false;
HistoryBlock *block = pushBackNewBlock();
block->items.reserve(slice.size() + (collapsed ? collapsed->size() : 0));
for (auto i = slice.cend(), e = slice.cbegin(); i != e;) { for (auto i = slice.cend(), e = slice.cbegin(); i != e;) {
--i; --i;
HistoryItem *adding = createItem(*i, false, true); HistoryItem *adding = createItem(*i, false, true);
@ -1858,25 +1843,22 @@ void History::addNewerSlice(const QVector<MTPMessage> &slice, const QVector<MTPM
const MTPDmessageGroup &group(groupsIt->c_messageGroup()); const MTPDmessageGroup &group(groupsIt->c_messageGroup());
if (group.vmin_id.v >= adding->id) break; 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) { for (; groupsIt != groupsEnd; ++groupsIt) {
if (groupsIt->type() != mtpc_messageGroup) continue; if (groupsIt->type() != mtpc_messageGroup) continue;
const MTPDmessageGroup &group(groupsIt->c_messageGroup()); const MTPDmessageGroup &group(groupsIt->c_messageGroup());
prev = addMessageGroupAfterPrevToBlock(group, prev, block); addMessageGroup(group);
} }
if (block->items.isEmpty()) { if (!atLeastOneAdded) {
newLoaded = true; newLoaded = true;
setLastMessage(lastImportantMessage()); setLastMessage(lastImportantMessage());
blocks.pop_back();
delete block;
block = nullptr;
} }
} }
@ -2176,21 +2158,70 @@ HistoryItem *History::addNewInTheMiddle(HistoryItem *newItem, int32 blockIndex,
return newItem; return newItem;
} }
HistoryBlock *History::pushBackNewBlock() { template <typename CreateGroup, typename UniteGroup>
HistoryBlock *result = new HistoryBlock(this); void History::addMessageGroup(CreateGroup create, UniteGroup unite) {
result->setIndexInHistory(blocks.size()); HistoryItem *previous = nullptr;
blocks.push_back(result); if (isBuildingFrontBlock()) {
return result; 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<HistoryGroup*>(previous));
} else {
addItemToBlock(create(previous));
}
} }
HistoryBlock *History::pushFrontNewBlock() { void History::addMessageGroup(const MTPDmessageGroup &group) {
HistoryBlock *result = new HistoryBlock(this); addMessageGroup([&group, this](HistoryItem *previous) -> HistoryGroup* { // create(..)
result->setIndexInHistory(0); return HistoryGroup::create(this, group, previous ? previous->date : date(group.vdate));
blocks.push_front(result); }, [&group](HistoryGroup *existing) { // unite(..)
for (int i = 1, l = blocks.size(); i < l; ++i) { existing->uniteWith(group.vmin_id.v, group.vmax_id.v, group.vcount.v);
blocks.at(i)->setIndexInHistory(i); });
}
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<HistoryGroup*>(first)->uniteWith(static_cast<HistoryGroup*>(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() { void History::clearNotifications() {
@ -2567,6 +2598,10 @@ void History::changeMsgId(MsgId oldId, MsgId newId) {
void History::removeBlock(HistoryBlock *block) { void History::removeBlock(HistoryBlock *block) {
t_assert(block->items.isEmpty()); t_assert(block->items.isEmpty());
if (_buildingFrontBlock && block == _buildingFrontBlock->block) {
_buildingFrontBlock->block = nullptr;
}
int index = block->indexInHistory(); int index = block->indexInHistory();
blocks.removeAt(index); blocks.removeAt(index);
for (int i = index, l = blocks.size(); i < l; ++i) { for (int i = index, l = blocks.size(); i < l; ++i) {
@ -3017,13 +3052,17 @@ void HistoryMessageUnreadBar::init(int count) {
_width = st::semiboldFont->width(_text); _width = st::semiboldFont->width(_text);
} }
int HistoryMessageUnreadBar::height() const { int HistoryMessageUnreadBar::height() {
return st::unreadBarHeight; return st::unreadBarHeight + st::unreadBarMargin;
}
int HistoryMessageUnreadBar::marginTop() {
return st::lineWidth + st::unreadBarMargin;
} }
void HistoryMessageUnreadBar::paint(Painter &p, int y, int w) const { 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 + marginTop(), w, height() - marginTop() - st::lineWidth, st::unreadBarBG);
p.fillRect(0, y + st::unreadBarHeight - st::lineWidth, w, st::lineWidth, st::unreadBarBorder); p.fillRect(0, y + height() - st::lineWidth, w, st::lineWidth, st::unreadBarBorder);
p.setFont(st::unreadBarFont); p.setFont(st::unreadBarFont);
p.setPen(st::unreadBarColor); p.setPen(st::unreadBarColor);
@ -3034,7 +3073,7 @@ void HistoryMessageUnreadBar::paint(Painter &p, int y, int w) const {
} }
w = maxwidth; 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) { void HistoryMessageDate::init(const QDateTime &date) {
@ -3128,6 +3167,7 @@ void HistoryItem::destroy() {
if ((!out() || isPost()) && unread() && history()->unreadCount > 0) { if ((!out() || isPost()) && unread() && history()->unreadCount > 0) {
history()->setUnreadCount(history()->unreadCount - 1); history()->setUnreadCount(history()->unreadCount - 1);
} }
Global::RefPendingRepaintItems().remove(this);
delete this; delete this;
} }
@ -3334,7 +3374,7 @@ void RadialAnimation::update(float64 prg, bool finished, uint64 ms) {
_opacity *= 1 - r; _opacity *= 1 - r;
} }
float64 fromstart = fulldt / st::radialPeriod; 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() { void RadialAnimation::stop() {
@ -5155,7 +5195,7 @@ void HistorySticker::draw(Painter &p, const HistoryItem *parent, const QRect &r,
} }
if (parent->getMedia() == this) { 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) { if (reply) {
int32 rw = _width - usew - st::msgReplyPadding.left(), rh = st::msgReplyPadding.top() + st::msgReplyBarSize.height() + st::msgReplyPadding.bottom(); 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 { void HistoryMessage::drawInfo(Painter &p, int32 right, int32 bottom, int32 width, bool selected, InfoDisplayType type) const {
p.setFont(st::msgDateFont); 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; int32 infoRight = right, infoBottom = bottom;
switch (type) { switch (type) {
case InfoDisplayDefault: case InfoDisplayDefault:
infoRight -= st::msgPadding.right() - st::msgDateDelta.x(); infoRight -= st::msgPadding.right() - st::msgDateDelta.x();
infoBottom -= st::msgPadding.bottom() - st::msgDateDelta.y(); 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; break;
case InfoDisplayOverImage: case InfoDisplayOverImage:
infoRight -= st::msgDateImgDelta + st::msgDateImgPadding.x(); infoRight -= st::msgDateImgDelta + st::msgDateImgPadding.x();
infoBottom -= st::msgDateImgDelta + st::msgDateImgPadding.y(); 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; break;
} }
@ -7019,6 +7065,9 @@ void HistoryMessage::drawInfo(Painter &p, int32 right, int32 bottom, int32 width
if (type == InfoDisplayOverImage) { if (type == InfoDisplayOverImage) {
int32 dateW = infoW + 2 * st::msgDateImgPadding.x(), dateH = st::msgDateFont->height + 2 * st::msgDateImgPadding.y(); 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); 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(); 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()); iconPos = QPoint(infoRight - infoW + st::msgViewsPos.x(), infoBottom - st::msgViewsImg.pxHeight() + st::msgViewsPos.y());
if (id > 0) { if (id > 0) {
if (outbg) { if (outbg) {
iconRect = &(overimg ? st::msgInvViewsImg : (selected ? st::msgSelectOutViewsImg : st::msgOutViewsImg)); iconRect = &(invertedsprites ? st::msgInvViewsImg : (selected ? st::msgSelectOutViewsImg : st::msgOutViewsImg));
} else { } 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); p.drawText(iconPos.x() + st::msgViewsImg.pxWidth() + st::msgDateCheckSpace, infoBottom - st::msgDateFont->descent, views->_viewsText);
} else { } else {
iconPos.setX(iconPos.x() + st::msgDateViewsSpace + views->_viewsWidth); iconPos.setX(iconPos.x() + st::msgDateViewsSpace + views->_viewsWidth);
if (outbg) { if (outbg) {
iconRect = &(overimg ? st::msgInvSendingViewsImg : st::msgSendingOutViewsImg); iconRect = &(invertedsprites ? st::msgInvSendingViewsImg : st::msgSendingOutViewsImg);
} else { } else {
iconRect = &(overimg ? st::msgInvSendingViewsImg : st::msgSendingViewsImg); iconRect = &(invertedsprites ? st::msgInvSendingViewsImg : st::msgSendingViewsImg);
} }
} }
p.drawPixmap(iconPos, App::sprite(), *iconRect); p.drawPixmap(iconPos, App::sprite(), *iconRect);
} else if (id < 0 && history()->peer->isSelf()) { } else if (id < 0 && history()->peer->isSelf()) {
iconPos = QPoint(infoRight - infoW, infoBottom - st::msgViewsImg.pxHeight() + st::msgViewsPos.y()); 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); p.drawPixmap(iconPos, App::sprite(), *iconRect);
} }
if (outbg) { if (outbg) {
iconPos = QPoint(infoRight - st::msgCheckImg.pxWidth() + st::msgCheckPos.x(), infoBottom - st::msgCheckImg.pxHeight() + st::msgCheckPos.y()); iconPos = QPoint(infoRight - st::msgCheckImg.pxWidth() + st::msgCheckPos.x(), infoBottom - st::msgCheckImg.pxHeight() + st::msgCheckPos.y());
if (id > 0) { if (id > 0) {
if (unread()) { if (unread()) {
iconRect = &(overimg ? st::msgInvCheckImg : (selected ? st::msgSelectCheckImg : st::msgCheckImg)); iconRect = &(invertedsprites ? st::msgInvCheckImg : (selected ? st::msgSelectCheckImg : st::msgCheckImg));
} else { } else {
iconRect = &(overimg ? st::msgInvDblCheckImg : (selected ? st::msgSelectDblCheckImg : st::msgDblCheckImg)); iconRect = &(invertedsprites ? st::msgInvDblCheckImg : (selected ? st::msgSelectDblCheckImg : st::msgDblCheckImg));
} }
} else { } else {
iconRect = &(overimg ? st::msgInvSendingImg : st::msgSendingImg); iconRect = &(invertedsprites ? st::msgInvSendingImg : st::msgSendingImg);
} }
p.drawPixmap(iconPos, App::sprite(), *iconRect); p.drawPixmap(iconPos, App::sprite(), *iconRect);
} }

View file

@ -470,19 +470,64 @@ protected:
void clearOnDestroy(); void clearOnDestroy();
HistoryItem *addNewToLastBlock(const MTPMessage &msg, NewMessageType type); 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 <typename CreateGroup, typename UniteGroup>
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: private:
enum Flag { enum class Flag {
f_has_pending_resized_items = (1 << 0), f_has_pending_resized_items = (1 << 0),
f_pending_resize = (1 << 1), f_pending_resize = (1 << 1),
}; };
Q_DECLARE_FLAGS(Flags, Flag); Q_DECLARE_FLAGS(Flags, Flag);
Q_DECL_CONSTEXPR friend inline QFlags<Flags::enum_type> operator|(Flags::enum_type f1, Flags::enum_type f2) Q_DECL_NOTHROW { Q_DECL_CONSTEXPR friend inline QFlags<Flags::enum_type> operator|(Flags::enum_type f1, Flags::enum_type f2) noexcept {
return QFlags<Flags::enum_type>(f1) | f2; return QFlags<Flags::enum_type>(f1) | f2;
} }
Q_DECL_CONSTEXPR friend inline QFlags<Flags::enum_type> operator|(Flags::enum_type f1, QFlags<Flags::enum_type> f2) Q_DECL_NOTHROW { Q_DECL_CONSTEXPR friend inline QFlags<Flags::enum_type> operator|(Flags::enum_type f1, QFlags<Flags::enum_type> f2) noexcept {
return f2 | f1; return f2 | f1;
} }
Q_DECL_CONSTEXPR friend inline QFlags<Flags::enum_type> operator~(Flags::enum_type f) noexcept {
return ~QFlags<Flags::enum_type>(f);
}
Flags _flags; Flags _flags;
ChatListLinksMap _chatListLinks; ChatListLinksMap _chatListLinks;
@ -497,28 +542,18 @@ private:
MediaOverviewIds overviewIds[OverviewCount]; MediaOverviewIds overviewIds[OverviewCount];
int32 overviewCountData[OverviewCount]; // -1 - not loaded, 0 - all loaded, > 0 - count, but not all loaded int32 overviewCountData[OverviewCount]; // -1 - not loaded, 0 - all loaded, > 0 - count, but not all loaded
friend class HistoryBlock; // A pointer to the block that is currently being built.
friend class ChannelHistory; // 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<BuildingBlock> _buildingFrontBlock;
// this method just removes a block from the blocks list // Creates if necessary a new block for adding item.
// when the last item from this block was detached and // Depending on isBuildingFrontBlock() gets front or back block.
// calls the required previousItemChanged() HistoryBlock *prepareBlockForAddingItem();
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();
}; };
@ -952,6 +987,7 @@ enum HistoryCursorState {
enum InfoDisplayType { enum InfoDisplayType {
InfoDisplayDefault, InfoDisplayDefault,
InfoDisplayOverImage, InfoDisplayOverImage,
InfoDisplayOverBackground,
}; };
inline bool isImportantChannelMessage(MsgId id, MTPDmessage::Flags flags) { // client-side important msgs always has_views or has_from_id 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<HistoryMessageDate> {
struct HistoryMessageUnreadBar : public BaseComponent<HistoryMessageUnreadBar> { struct HistoryMessageUnreadBar : public BaseComponent<HistoryMessageUnreadBar> {
void init(int count); void init(int count);
int height() const; static int height();
static int marginTop();
void paint(Painter &p, int y, int w) const; void paint(Painter &p, int y, int w) const;
QString _text; QString _text;
@ -1695,8 +1733,11 @@ protected:
HistoryItem *previous() const { HistoryItem *previous() const {
if (_block && _indexInBlock >= 0) { 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()) { if (HistoryBlock *previousBlock = _block->previous()) {
t_assert(!previousBlock->items.isEmpty());
return previousBlock->items.back(); return previousBlock->items.back();
} }
} }

View file

@ -190,9 +190,17 @@ void HistoryInner::enumerateUserpicsInHistory(History *h, int htop, Method metho
} }
void HistoryInner::paintEvent(QPaintEvent *e) { 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); Painter p(this);
QRect r(e->rect()); QRect r(e->rect());
@ -1643,7 +1651,9 @@ void HistoryInner::onTouchSelect() {
} }
void HistoryInner::onUpdateSelected() { void HistoryInner::onUpdateSelected() {
if (!_history) return; if (!_history || _history->hasPendingResizedItems() || (_migrated && _migrated->hasPendingResizedItems())) {
return;
}
QPoint mousePos(mapFromGlobal(_dragPos)); QPoint mousePos(mapFromGlobal(_dragPos));
QPoint point(_widget->clampMousePosition(mousePos)); QPoint point(_widget->clampMousePosition(mousePos));
@ -6178,7 +6188,7 @@ void HistoryWidget::notify_automaticLoadSettingsChangedGif() {
} }
void HistoryWidget::notify_handlePendingHistoryUpdate() { void HistoryWidget::notify_handlePendingHistoryUpdate() {
if (_history && _history->hasPendingResizedItems()) { if ((_history && _history->hasPendingResizedItems()) || (_migrated && _migrated->hasPendingResizedItems())) {
updateListSize(); updateListSize();
_list->update(); _list->update();
} }
@ -6324,7 +6334,9 @@ void HistoryWidget::updateListSize(bool initial, bool loadedDown, const ScrollCh
if (_pinnedBar) { if (_pinnedBar) {
newScrollHeight -= st::replyHeight; 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) { if (needResize) {
_scroll.resize(width(), newScrollHeight); _scroll.resize(width(), newScrollHeight);
// on initial updateListSize we didn't put the _scroll.scrollTop correctly yet // 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()))) { 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) { if (change.type == ScrollChangeAdd) {
addToY = change.value; toY += change.value;
} else if (change.type == ScrollChangeOldHistoryHeight) { } else if (change.type == ScrollChangeNoJumpToBottom) {
addToY = _list->historyHeight() - change.value; 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) { if (_scroll.scrollTop() == toY) {
visibleAreaUpdated(); visibleAreaUpdated();
} else { } else {
@ -6435,13 +6448,11 @@ void HistoryWidget::updateListSize(bool initial, bool loadedDown, const ScrollCh
} else { } else {
toY = qMax(iy + item->height() - _fixedInScrollMsgTop, 0); toY = qMax(iy + item->height() - _fixedInScrollMsgTop, 0);
} }
} else if (initial && _migrated && _migrated->unreadBar) { } else if (initial && (_history->unreadBar || (_migrated && _migrated->unreadBar))) {
toY = _list->itemTop(_migrated->unreadBar); toY = unreadBarTop();
} else if (initial && _history->unreadBar) {
toY = _list->itemTop(_history->unreadBar);
} else if (_migrated && _migrated->showFrom) { } else if (_migrated && _migrated->showFrom) {
toY = _list->itemTop(_migrated->showFrom); toY = _list->itemTop(_migrated->showFrom);
if (toY < _scroll.scrollTopMax() + st::unreadBarHeight) { if (toY < _scroll.scrollTopMax() + HistoryMessageUnreadBar::height() - HistoryMessageUnreadBar::marginTop()) {
_migrated->addUnreadBar(); _migrated->addUnreadBar();
if (_migrated->unreadBar) { if (_migrated->unreadBar) {
setMsgId(ShowAtUnreadMsgId); 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<HistoryMessageDate>()) {
result += bar->Get<HistoryMessageDate>()->height();
}
return result;
}
return -1;
}
void HistoryWidget::addMessagesToFront(PeerData *peer, const QVector<MTPMessage> &messages, const QVector<MTPMessageGroup> *collapsed) { void HistoryWidget::addMessagesToFront(PeerData *peer, const QVector<MTPMessage> &messages, const QVector<MTPMessageGroup> *collapsed) {
int oldH = _list->historyHeight(); int oldH = _list->historyHeight();
_list->messagesReceived(peer, messages, collapsed); _list->messagesReceived(peer, messages, collapsed);
@ -6491,7 +6522,7 @@ void HistoryWidget::addMessagesToFront(PeerData *peer, const QVector<MTPMessage>
void HistoryWidget::addMessagesToBack(PeerData *peer, const QVector<MTPMessage> &messages, const QVector<MTPMessageGroup> *collapsed) { void HistoryWidget::addMessagesToBack(PeerData *peer, const QVector<MTPMessage> &messages, const QVector<MTPMessageGroup> *collapsed) {
_list->messagesReceivedDown(peer, messages, collapsed); _list->messagesReceivedDown(peer, messages, collapsed);
if (!_firstLoadRequest) { if (!_firstLoadRequest) {
updateListSize(false, true); updateListSize(false, true, { ScrollChangeNoJumpToBottom, 0 });
} }
} }
@ -6875,7 +6906,10 @@ bool HistoryWidget::pinnedMsgVisibilityUpdated() {
_topShadow.raise(); _topShadow.raise();
updatePinnedBar(); updatePinnedBar();
result = true; result = true;
_scroll.scrollToY(_scroll.scrollTop() + st::replyHeight);
if (_scroll.scrollTop() != unreadBarTop()) {
_scroll.scrollToY(_scroll.scrollTop() + st::replyHeight);
}
} else if (_pinnedBar->msgId != pinnedMsgId) { } else if (_pinnedBar->msgId != pinnedMsgId) {
_pinnedBar->msgId = pinnedMsgId; _pinnedBar->msgId = pinnedMsgId;
_pinnedBar->msg = 0; _pinnedBar->msg = 0;
@ -6889,7 +6923,9 @@ bool HistoryWidget::pinnedMsgVisibilityUpdated() {
} else if (_pinnedBar) { } else if (_pinnedBar) {
destroyPinnedBar(); destroyPinnedBar();
result = true; result = true;
_scroll.scrollToY(_scroll.scrollTop() - st::replyHeight); if (_scroll.scrollTop() != unreadBarTop()) {
_scroll.scrollToY(_scroll.scrollTop() - st::replyHeight);
}
resizeEvent(0); resizeEvent(0);
} }
return result; return result;

View file

@ -864,8 +864,12 @@ private:
enum ScrollChangeType { enum ScrollChangeType {
ScrollChangeNone, ScrollChangeNone,
// When we toggle a pinned message.
ScrollChangeAdd, ScrollChangeAdd,
ScrollChangeOldHistoryHeight,
// When loading a history part while scrolling down.
ScrollChangeNoJumpToBottom,
}; };
struct ScrollChange { struct ScrollChange {
ScrollChangeType type; ScrollChangeType type;
@ -873,6 +877,10 @@ private:
}; };
void updateListSize(bool initial = false, bool loadedDown = false, const ScrollChange &change = { ScrollChangeNone, 0 }); 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 saveGifDone(DocumentData *doc, const MTPBool &result);
void reportSpamDone(PeerData *peer, const MTPBool &result, mtpRequestId request); void reportSpamDone(PeerData *peer, const MTPBool &result, mtpRequestId request);

View file

@ -614,119 +614,127 @@ void _moveOldDataFiles(const QString &wasDir) {
namespace SignalHandlers { namespace SignalHandlers {
typedef std::map<std::string, std::string> AnnotationsMap; namespace internal {
AnnotationsMap ProcessAnnotations; using Annotations = std::map<std::string, std::string>;
using AnnotationRefs = std::map<std::string, const QString*>;
Annotations ProcessAnnotations;
AnnotationRefs ProcessAnnotationRefs;
#ifndef TDESKTOP_DISABLE_CRASH_REPORTS #ifndef TDESKTOP_DISABLE_CRASH_REPORTS
QString CrashDumpPath; QString ReportPath;
FILE *CrashDumpFile = nullptr; FILE *ReportFile = nullptr;
int CrashDumpFileNo = 0; int ReportFileNo = 0;
char LaunchedDateTimeStr[32] = { 0 }; char LaunchedDateTimeStr[32] = { 0 };
char LaunchedBinaryName[256] = { 0 }; char LaunchedBinaryName[256] = { 0 };
void _writeChar(char ch) { void writeChar(char ch) {
fwrite(&ch, 1, 1, CrashDumpFile); 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 <bool Unsigned, typename Type> template <bool Unsigned, typename Type>
struct _writeNumberSignAndRemoveIt { struct writeNumberSignAndRemoveIt {
static void call(Type &number) { static void call(Type &number) {
if (number < 0) { if (number < 0) {
_writeChar('-'); writeChar('-');
number = -number; number = -number;
} }
} }
}; };
template <typename Type> template <typename Type>
struct _writeNumberSignAndRemoveIt<true, Type> { struct writeNumberSignAndRemoveIt<true, Type> {
static void call(Type &number) { static void call(Type &number) {
} }
}; };
template <typename Type> template <typename Type>
const dump &_writeNumber(const dump &stream, Type number) { const dump &writeNumber(const dump &stream, Type number) {
if (!CrashDumpFile) return stream; 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; Type upper = 1, prev = number / 10;
while (prev >= upper) { while (prev >= upper) {
upper *= 10; upper *= 10;
} }
while (upper > 0) { while (upper > 0) {
int digit = (number / upper); int digit = (number / upper);
_writeChar('0' + digit); internal::writeChar('0' + digit);
number -= digit * upper; number -= digit * upper;
upper /= 10; upper /= 10;
} }
return stream; 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) { 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) { 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) { 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) { 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) { const dump &operator<<(const dump &stream, double num) {
if (num < 0) { if (num < 0) {
_writeChar('-'); internal::writeChar('-');
num = -num; num = -num;
} }
_writeNumber(stream, uint64(floor(num))); internal::writeNumber(stream, uint64(floor(num)));
_writeChar('.'); internal::writeChar('.');
num -= floor(num); num -= floor(num);
for (int i = 0; i < 4; ++i) { for (int i = 0; i < 4; ++i) {
num *= 10; num *= 10;
int digit = int(floor(num)); int digit = int(floor(num));
_writeChar('0' + digit); internal::writeChar('0' + digit);
num -= digit; num -= digit;
} }
return stream; return stream;
} }
Qt::HANDLE LoggingCrashThreadId = 0; namespace internal {
bool LoggingCrashHeaderWritten = false;
QMutex LoggingCrashMutex;
const char *BreakpadDumpPath = 0; Qt::HANDLE ReportingThreadId = nullptr;
const wchar_t *BreakpadDumpPathW = 0; 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 #if defined Q_OS_MAC || defined Q_OS_LINUX32 || defined Q_OS_LINUX64
struct sigaction SIG_def[32]; struct sigaction SIG_def[32];
@ -753,14 +761,34 @@ namespace SignalHandlers {
} }
Qt::HANDLE thread = QThread::currentThreadId(); Qt::HANDLE thread = QThread::currentThreadId();
if (thread == LoggingCrashThreadId) return; if (thread == ReportingThreadId) return;
QMutexLocker lock(&LoggingCrashMutex); QMutexLocker lock(&ReportingMutex);
LoggingCrashThreadId = thread; ReportingThreadId = thread;
if (!LoggingCrashHeaderWritten) { if (!ReportingHeaderWritten) {
LoggingCrashHeaderWritten = true; ReportingHeaderWritten = true;
const AnnotationsMap c_ProcessAnnotations(ProcessAnnotations); 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<uchar>(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) { for (const auto &i : c_ProcessAnnotations) {
dump() << i.first.c_str() << ": " << i.second.c_str() << "\n"; dump() << i.first.c_str() << ": " << i.second.c_str() << "\n";
} }
@ -843,7 +871,7 @@ namespace SignalHandlers {
dump() << "\nBacktrace:\n"; 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 #else // Q_OS_MAC || Q_OS_LINUX32 || Q_OS_LINUX64
dump() << "\nBacktrace:\n"; dump() << "\nBacktrace:\n";
@ -853,7 +881,7 @@ namespace SignalHandlers {
dump() << "\n"; dump() << "\n";
LoggingCrashThreadId = 0; ReportingThreadId = nullptr;
} }
bool SetSignalHandlers = true; bool SetSignalHandlers = true;
@ -890,8 +918,12 @@ namespace SignalHandlers {
#endif // !TDESKTOP_DISABLE_CRASH_REPORTS #endif // !TDESKTOP_DISABLE_CRASH_REPORTS
} // namespace internal
void StartCrashHandler() { void StartCrashHandler() {
#ifndef TDESKTOP_DISABLE_CRASH_REPORTS #ifndef TDESKTOP_DISABLE_CRASH_REPORTS
using internal::ProcessAnnotations;
ProcessAnnotations["Binary"] = cExeName().toUtf8().constData(); ProcessAnnotations["Binary"] = cExeName().toUtf8().constData();
ProcessAnnotations["ApiId"] = QString::number(ApiId).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(); 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); QDir().mkpath(dumpspath);
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
BreakpadExceptionHandler = new google_breakpad::ExceptionHandler( internal::BreakpadExceptionHandler = new google_breakpad::ExceptionHandler(
dumpspath.toStdWString(), dumpspath.toStdWString(),
/*FilterCallback*/ 0, /*FilterCallback*/ 0,
DumpCallback, internal::DumpCallback,
/*context*/ 0, /*context*/ 0,
true true
); );
@ -914,16 +946,16 @@ namespace SignalHandlers {
#ifdef MAC_USE_BREAKPAD #ifdef MAC_USE_BREAKPAD
#ifndef _DEBUG #ifndef _DEBUG
BreakpadExceptionHandler = new google_breakpad::ExceptionHandler( internal::BreakpadExceptionHandler = new google_breakpad::ExceptionHandler(
QFile::encodeName(dumpspath).toStdString(), QFile::encodeName(dumpspath).toStdString(),
/*FilterCallback*/ 0, /*FilterCallback*/ 0,
DumpCallback, internal::DumpCallback,
/*context*/ 0, /*context*/ 0,
true, true,
0 0
); );
#endif // !_DEBUG #endif // !_DEBUG
SetSignalHandlers = false; internal::SetSignalHandlers = false;
#else // MAC_USE_BREAKPAD #else // MAC_USE_BREAKPAD
crashpad::CrashpadClient crashpad_client; crashpad::CrashpadClient crashpad_client;
std::string handler = (cExeDir() + cExeName() + qsl("/Contents/Helpers/crashpad_handler")).toUtf8().constData(); std::string handler = (cExeDir() + cExeName() + qsl("/Contents/Helpers/crashpad_handler")).toUtf8().constData();
@ -938,10 +970,10 @@ namespace SignalHandlers {
} }
#endif // else for MAC_USE_BREAKPAD #endif // else for MAC_USE_BREAKPAD
#elif defined Q_OS_LINUX64 || defined Q_OS_LINUX32 #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()), google_breakpad::MinidumpDescriptor(QFile::encodeName(dumpspath).toStdString()),
/*FilterCallback*/ 0, /*FilterCallback*/ 0,
DumpCallback, internal::DumpCallback,
/*context*/ 0, /*context*/ 0,
true, true,
-1 -1
@ -954,9 +986,8 @@ namespace SignalHandlers {
#ifndef TDESKTOP_DISABLE_CRASH_REPORTS #ifndef TDESKTOP_DISABLE_CRASH_REPORTS
#if !defined Q_OS_MAC || defined MAC_USE_BREAKPAD #if !defined Q_OS_MAC || defined MAC_USE_BREAKPAD
if (BreakpadExceptionHandler) { if (internal::BreakpadExceptionHandler) {
google_breakpad::ExceptionHandler *h = BreakpadExceptionHandler; google_breakpad::ExceptionHandler *h = getPointerAndReset(internal::BreakpadExceptionHandler);
BreakpadExceptionHandler = 0;
delete h; delete h;
} }
#endif // !Q_OS_MAC || MAC_USE_BREAKPAD #endif // !Q_OS_MAC || MAC_USE_BREAKPAD
@ -966,15 +997,16 @@ namespace SignalHandlers {
Status start() { Status start() {
#ifndef TDESKTOP_DISABLE_CRASH_REPORTS #ifndef TDESKTOP_DISABLE_CRASH_REPORTS
CrashDumpPath = cWorkingDir() + qsl("tdata/working"); using internal::ReportPath;
ReportPath = cWorkingDir() + qsl("tdata/working");
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
FILE *f = nullptr; 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; f = nullptr;
} else { } else {
#else // !Q_OS_WIN #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 #endif // else for !Q_OS_WIN
QByteArray lastdump; QByteArray lastdump;
char buffer[256 * 1024] = { 0 }; char buffer[256 * 1024] = { 0 };
@ -986,7 +1018,7 @@ namespace SignalHandlers {
Sandbox::SetLastCrashDump(lastdump); 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; return LastCrashed;
} }
@ -997,48 +1029,48 @@ namespace SignalHandlers {
Status restart() { Status restart() {
#ifndef TDESKTOP_DISABLE_CRASH_REPORTS #ifndef TDESKTOP_DISABLE_CRASH_REPORTS
if (CrashDumpFile) { if (internal::ReportFile) {
return Started; return Started;
} }
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
if (_wfopen_s(&CrashDumpFile, CrashDumpPath.toStdWString().c_str(), L"wb") != 0) { if (_wfopen_s(&internal::ReportFile, internal::ReportPath.toStdWString().c_str(), L"wb") != 0) {
CrashDumpFile = nullptr; internal::ReportFile = nullptr;
} }
#else // Q_OS_WIN #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 #endif // else for Q_OS_WIN
if (CrashDumpFile) { if (internal::ReportFile) {
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
CrashDumpFileNo = _fileno(CrashDumpFile); internal::ReportFileNo = _fileno(internal::ReportFile);
#else // Q_OS_WIN #else // Q_OS_WIN
CrashDumpFileNo = fileno(CrashDumpFile); internal::ReportFileNo = fileno(internal::ReportFile);
#endif // else for Q_OS_WIN #endif // else for Q_OS_WIN
if (SetSignalHandlers) { if (internal::SetSignalHandlers) {
#ifndef Q_OS_WIN #ifndef Q_OS_WIN
struct sigaction sigact; struct sigaction sigact;
sigact.sa_sigaction = SignalHandlers::Handler; sigact.sa_sigaction = SignalHandlers::internal::Handler;
sigemptyset(&sigact.sa_mask); sigemptyset(&sigact.sa_mask);
sigact.sa_flags = SA_NODEFER | SA_RESETHAND | SA_SIGINFO; sigact.sa_flags = SA_NODEFER | SA_RESETHAND | SA_SIGINFO;
sigaction(SIGABRT, &sigact, &SIG_def[SIGABRT]); sigaction(SIGABRT, &sigact, &internal::SIG_def[SIGABRT]);
sigaction(SIGSEGV, &sigact, &SIG_def[SIGSEGV]); sigaction(SIGSEGV, &sigact, &internal::SIG_def[SIGSEGV]);
sigaction(SIGILL, &sigact, &SIG_def[SIGILL]); sigaction(SIGILL, &sigact, &internal::SIG_def[SIGILL]);
sigaction(SIGFPE, &sigact, &SIG_def[SIGFPE]); sigaction(SIGFPE, &sigact, &internal::SIG_def[SIGFPE]);
sigaction(SIGBUS, &sigact, &SIG_def[SIGBUS]); sigaction(SIGBUS, &sigact, &internal::SIG_def[SIGBUS]);
sigaction(SIGSYS, &sigact, &SIG_def[SIGSYS]); sigaction(SIGSYS, &sigact, &internal::SIG_def[SIGSYS]);
#else // !Q_OS_WIN #else // !Q_OS_WIN
signal(SIGABRT, SignalHandlers::Handler); signal(SIGABRT, SignalHandlers::internal::Handler);
signal(SIGSEGV, SignalHandlers::Handler); signal(SIGSEGV, SignalHandlers::internal::Handler);
signal(SIGILL, SignalHandlers::Handler); signal(SIGILL, SignalHandlers::internal::Handler);
signal(SIGFPE, SignalHandlers::Handler); signal(SIGFPE, SignalHandlers::internal::Handler);
#endif // else for !Q_OS_WIN #endif // else for !Q_OS_WIN
} }
return Started; 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; return CantOpen;
#else // !TDESKTOP_DISABLE_CRASH_REPORTS #else // !TDESKTOP_DISABLE_CRASH_REPORTS
@ -1049,29 +1081,33 @@ namespace SignalHandlers {
void finish() { void finish() {
#ifndef TDESKTOP_DISABLE_CRASH_REPORTS #ifndef TDESKTOP_DISABLE_CRASH_REPORTS
FinishCrashHandler(); FinishCrashHandler();
if (CrashDumpFile) { if (internal::ReportFile) {
fclose(CrashDumpFile); fclose(internal::ReportFile);
CrashDumpFile = nullptr; internal::ReportFile = nullptr;
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
_wunlink(CrashDumpPath.toStdWString().c_str()); _wunlink(internal::ReportPath.toStdWString().c_str());
#else // Q_OS_WIN #else // Q_OS_WIN
unlink(CrashDumpPath.toUtf8().constData()); unlink(internal::ReportPath.toUtf8().constData());
#endif // else for Q_OS_WIN #endif // else for Q_OS_WIN
} }
#endif // !TDESKTOP_DISABLE_CRASH_REPORTS #endif // !TDESKTOP_DISABLE_CRASH_REPORTS
} }
void setSelfUsername(const QString &username) { void setCrashAnnotation(const std::string &key, const QString &value) {
if (username.trimmed().isEmpty()) { if (!value.trimmed().isEmpty()) {
ProcessAnnotations.erase("Username"); internal::ProcessAnnotations[key] = value.toUtf8().constData();
} else { } else {
ProcessAnnotations["Username"] = username.toUtf8().constData(); internal::ProcessAnnotations.erase(key);
} }
} }
void setAssertionInfo(const QString &info) { void setCrashAnnotationRef(const std::string &key, const QString *valuePtr) {
ProcessAnnotations["Assertion"] = info.toUtf8().constData(); if (valuePtr) {
internal::ProcessAnnotationRefs[key] = valuePtr;
} else {
internal::ProcessAnnotationRefs.erase(key);
}
} }
} }

View file

@ -107,7 +107,13 @@ namespace SignalHandlers {
Status restart(); // can be only CantOpen or Started Status restart(); // can be only CantOpen or Started
void finish(); void finish();
void setSelfUsername(const QString &username); void setCrashAnnotation(const std::string &key, const QString &value);
void setAssertionInfo(const QString &info);
// 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);
}
} }

View file

@ -2973,9 +2973,7 @@ void MainWidget::feedMessageIds(const MTPVector<MTPUpdate> &updates) {
} }
bool MainWidget::updateFail(const RPCError &e) { bool MainWidget::updateFail(const RPCError &e) {
if (MTP::authedId()) { App::logOutDelayed();
App::logOut();
}
return true; return true;
} }
@ -3722,7 +3720,7 @@ bool MainWidget::inviteImportFail(const RPCError &error) {
void MainWidget::startFull(const MTPVector<MTPUser> &users) { void MainWidget::startFull(const MTPVector<MTPUser> &users) {
const QVector<MTPUser> &v(users.c_vector().v); const QVector<MTPUser> &v(users.c_vector().v);
if (v.isEmpty() || v[0].type() != mtpc_user || !v[0].c_user().is_self()) { // wtf?.. if (v.isEmpty() || v[0].type() != mtpc_user || !v[0].c_user().is_self()) { // wtf?..
return App::logOut(); return App::logOutDelayed();
} }
start(v[0]); start(v[0]);
} }

View file

@ -25,6 +25,8 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#ifdef __cplusplus #ifdef __cplusplus
#include <cmath>
#include <QtCore/QtCore> #include <QtCore/QtCore>
#include <QtWidgets/QtWidgets> #include <QtWidgets/QtWidgets>
#include <QtNetwork/QtNetwork> #include <QtNetwork/QtNetwork>

View file

@ -294,12 +294,12 @@ void as_const(const T&&) = delete;
#include "logs.h" #include "logs.h"
static volatile int *t_assert_nullptr = 0; static volatile int *t_assert_nullptr = nullptr;
inline void t_noop() {} inline void t_noop() {}
inline void t_assert_fail(const char *message, const char *file, int32 line) { 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)); QString info(qsl("%1 %2:%3").arg(message).arg(file).arg(line));
LOG(("Assertion Failed! %1 %2:%3").arg(info)); LOG(("Assertion Failed! %1 %2:%3").arg(info));
SignalHandlers::setAssertionInfo(info); SignalHandlers::setCrashAnnotation("Assertion", info);
*t_assert_nullptr = 0; *t_assert_nullptr = 0;
} }
#define t_assert_full(condition, message, file, line) ((!(condition)) ? t_assert_fail(message, file, line) : t_noop()) #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 mimeTypeForFile(const QFileInfo &file);
MimeType mimeTypeForData(const QByteArray &data); MimeType mimeTypeForData(const QByteArray &data);
inline int32 rowscount(int32 count, int32 perrow) { #include <cmath>
return (count + perrow - 1) / perrow;
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); return qMin(qMax(value / step, lowest), highest);
} }
inline int32 floorclamp(float64 value, int32 step, int32 lowest, int32 highest) { inline int floorclamp(float64 value, int step, int lowest, int highest) {
return qMin(qMax(qFloor(value / step), lowest), highest); return qMin(qMax(static_cast<int>(std::floor(value / step)), lowest), highest);
} }
inline int32 ceilclamp(int32 value, int32 step, int32 lowest, int32 highest) { inline int ceilclamp(int value, int step, int lowest, int highest) {
return qMax(qMin((value / step) + ((value % step) ? 1 : 0), highest), lowest); return qMax(qMin((value + step - 1) / step, highest), lowest);
} }
inline int32 ceilclamp(float64 value, int32 step, int32 lowest, int32 highest) { inline int ceilclamp(float64 value, int32 step, int32 lowest, int32 highest) {
return qMax(qMin(qCeil(value / step), highest), lowest); return qMax(qMin(static_cast<int>(std::ceil(value / step)), highest), lowest);
} }
enum ForwardWhatMessages { enum ForwardWhatMessages {

View file

@ -287,18 +287,20 @@ void NotifyWindow::startHiding() {
void NotifyWindow::mousePressEvent(QMouseEvent *e) { void NotifyWindow::mousePressEvent(QMouseEvent *e) {
if (!history) return; if (!history) return;
PeerId peer = history->peer->id; PeerId peer = history->peer->id;
MsgId msgId = (!history->peer->isUser() && item && item->mentionsMe() && item->id > 0) ? item->id : ShowAtUnreadMsgId;
if (e->button() == Qt::RightButton) { if (e->button() == Qt::RightButton) {
unlinkHistoryAndNotify(); unlinkHistoryAndNotify();
} else if (history) { } else {
App::wnd()->showFromTray(); App::wnd()->showFromTray();
if (App::passcoded()) { if (App::passcoded()) {
App::wnd()->setInnerFocus(); App::wnd()->setInnerFocus();
App::wnd()->notifyClear(); App::wnd()->notifyClear();
} else { } else {
App::wnd()->hideSettings(); App::wnd()->hideSettings();
Ui::showPeerHistory(peer, (!history->peer->isUser() && item && item->mentionsMe() && item->id > 0) ? item->id : ShowAtUnreadMsgId); Ui::showPeerHistory(peer, msgId);
} }
e->ignore(); e->ignore();
} }
@ -505,11 +507,8 @@ void Window::clearWidgets() {
settings = 0; settings = 0;
} }
if (main) { if (main) {
main->animStop_show(); delete main;
main->hide(); main = nullptr;
main->deleteLater();
main->rpcClear();
main = 0;
} }
if (intro) { if (intro) {
intro->stop_show(); intro->stop_show();
@ -691,7 +690,7 @@ void Window::setupMain(bool anim, const MTPUser *self) {
} }
void Window::updateCounter() { void Window::updateCounter() {
if (App::quitting()) return; if (!Global::started() || App::quitting()) return;
psUpdateCounter(); psUpdateCounter();
title->updateCounter(); title->updateCounter();
@ -1185,7 +1184,11 @@ void Window::onLogout() {
} }
void Window::onLogoutSure() { void Window::onLogoutSure() {
App::logOut(); if (MTP::authedId()) {
App::logOut();
} else {
setupIntro(true);
}
} }
void Window::updateGlobalMenu() { void Window::updateGlobalMenu() {
@ -1951,7 +1954,10 @@ PreLaunchWindow::PreLaunchWindow(QString title) : TWidget(0) {
tmp.setText(qsl("Tmp")); tmp.setText(qsl("Tmp"));
_size = tmp.sizeHint().height(); _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) { if (!PreLaunchWindowInstance) {
PreLaunchWindowInstance = this; PreLaunchWindowInstance = this;
} }

View file

@ -363,7 +363,7 @@ public:
PreLaunchWindow(QString title = QString()); PreLaunchWindow(QString title = QString());
void activate(); void activate();
float64 basicSize() const { int basicSize() const {
return _size; return _size;
} }
~PreLaunchWindow(); ~PreLaunchWindow();
@ -372,7 +372,7 @@ public:
protected: protected:
float64 _size; int _size;
}; };

View file

@ -11,7 +11,7 @@
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>
<string>APPL</string> <string>APPL</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>0.9.36</string> <string>0.9.39</string>
<key>CFBundleSignature</key> <key>CFBundleSignature</key>
<string>????</string> <string>????</string>
<key>CFBundleURLTypes</key> <key>CFBundleURLTypes</key>

View file

@ -34,8 +34,8 @@ IDI_ICON1 ICON "SourceFiles\\art\\icon256.ico"
// //
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 0,9,36,0 FILEVERSION 0,9,39,0
PRODUCTVERSION 0,9,36,0 PRODUCTVERSION 0,9,39,0
FILEFLAGSMASK 0x3fL FILEFLAGSMASK 0x3fL
#ifdef _DEBUG #ifdef _DEBUG
FILEFLAGS 0x1L FILEFLAGS 0x1L
@ -51,10 +51,10 @@ BEGIN
BLOCK "040904b0" BLOCK "040904b0"
BEGIN BEGIN
VALUE "CompanyName", "Telegram Messenger LLP" VALUE "CompanyName", "Telegram Messenger LLP"
VALUE "FileVersion", "0.9.36.0" VALUE "FileVersion", "0.9.39.0"
VALUE "LegalCopyright", "Copyright (C) 2014-2016" VALUE "LegalCopyright", "Copyright (C) 2014-2016"
VALUE "ProductName", "Telegram Desktop" VALUE "ProductName", "Telegram Desktop"
VALUE "ProductVersion", "0.9.36.0" VALUE "ProductVersion", "0.9.39.0"
END END
END END
BLOCK "VarFileInfo" BLOCK "VarFileInfo"

View file

@ -123,6 +123,7 @@
<OptimizeReferences>true</OptimizeReferences> <OptimizeReferences>true</OptimizeReferences>
<IgnoreSpecificDefaultLibraries> <IgnoreSpecificDefaultLibraries>
</IgnoreSpecificDefaultLibraries> </IgnoreSpecificDefaultLibraries>
<AdditionalOptions>/ignore:4099 %(AdditionalOptions)</AdditionalOptions>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">
@ -154,6 +155,7 @@
<OptimizeReferences>true</OptimizeReferences> <OptimizeReferences>true</OptimizeReferences>
<IgnoreSpecificDefaultLibraries> <IgnoreSpecificDefaultLibraries>
</IgnoreSpecificDefaultLibraries> </IgnoreSpecificDefaultLibraries>
<AdditionalOptions>/ignore:4099 %(AdditionalOptions)</AdditionalOptions>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemGroup> <ItemGroup>

View file

@ -1772,7 +1772,7 @@
buildSettings = { buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
COPY_PHASE_STRIP = NO; COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 0.9.36; CURRENT_PROJECT_VERSION = 0.9.39;
DEBUG_INFORMATION_FORMAT = dwarf; DEBUG_INFORMATION_FORMAT = dwarf;
GCC_GENERATE_DEBUGGING_SYMBOLS = YES; GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
GCC_OPTIMIZATION_LEVEL = 0; GCC_OPTIMIZATION_LEVEL = 0;
@ -1791,7 +1791,7 @@
buildSettings = { buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
COPY_PHASE_STRIP = YES; COPY_PHASE_STRIP = YES;
CURRENT_PROJECT_VERSION = 0.9.36; CURRENT_PROJECT_VERSION = 0.9.39;
GCC_GENERATE_DEBUGGING_SYMBOLS = NO; GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
GCC_OPTIMIZATION_LEVEL = fast; GCC_OPTIMIZATION_LEVEL = fast;
GCC_PREFIX_HEADER = ./SourceFiles/stdafx.h; GCC_PREFIX_HEADER = ./SourceFiles/stdafx.h;
@ -1820,10 +1820,10 @@
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = ""; CODE_SIGN_IDENTITY = "";
COPY_PHASE_STRIP = NO; COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 0.9.36; CURRENT_PROJECT_VERSION = 0.9.39;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DYLIB_COMPATIBILITY_VERSION = 0.9; DYLIB_COMPATIBILITY_VERSION = 0.9;
DYLIB_CURRENT_VERSION = 0.9.36; DYLIB_CURRENT_VERSION = 0.9.39;
ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_STRICT_OBJC_MSGSEND = YES;
FRAMEWORK_SEARCH_PATHS = ""; FRAMEWORK_SEARCH_PATHS = "";
GCC_GENERATE_DEBUGGING_SYMBOLS = YES; GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
@ -1961,10 +1961,10 @@
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = ""; CODE_SIGN_IDENTITY = "";
COPY_PHASE_STRIP = NO; COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 0.9.36; CURRENT_PROJECT_VERSION = 0.9.39;
DEBUG_INFORMATION_FORMAT = dwarf; DEBUG_INFORMATION_FORMAT = dwarf;
DYLIB_COMPATIBILITY_VERSION = 0.9; DYLIB_COMPATIBILITY_VERSION = 0.9;
DYLIB_CURRENT_VERSION = 0.9.36; DYLIB_CURRENT_VERSION = 0.9.39;
ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES; ENABLE_TESTABILITY = YES;
FRAMEWORK_SEARCH_PATHS = ""; FRAMEWORK_SEARCH_PATHS = "";

View file

@ -1,6 +1,6 @@
AppVersion 9036 AppVersion 9039
AppVersionStrMajor 0.9 AppVersionStrMajor 0.9
AppVersionStrSmall 0.9.36 AppVersionStrSmall 0.9.39
AppVersionStr 0.9.36 AppVersionStr 0.9.39
DevChannel 1 DevChannel 1
BetaVersion 0 9034004 BetaVersion 0 9034004

View file

@ -0,0 +1,91 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\..\SourceFiles\codegen\style\main.cpp" />
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{E4DF8176-4DEF-4859-962F-B497E3E7A323}</ProjectGuid>
<Keyword>Qt4VSv1.0</Keyword>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v140</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v140</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<_ProjectFileVersion>14.0.24730.2</_ProjectFileVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<OutDir>$(SolutionDir)$(Platform)\codegen\$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)$(Platform)\obj\$(ProjectName)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PreprocessorDefinitions>UNICODE;WIN32;QT_CORE_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Optimization>Disabled</Optimization>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<AdditionalIncludeDirectories>.;$(QTDIR)\include;.\GeneratedFiles\$(ConfigurationName);$(QTDIR)\include\QtCore;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<OutputFile>$(OutDir)\$(ProjectName).exe</OutputFile>
<AdditionalLibraryDirectories>$(QTDIR)\lib;$(QTDIR)\plugins;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>ws2_32.lib;qtmaind.lib;qtharfbuzzngd.lib;qtpcred.lib;qtfreetyped.lib;imageformats\qwebpd.lib;Qt5Cored.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<PreprocessorDefinitions>UNICODE;WIN32;QT_NO_DEBUG;NDEBUG;QT_CORE_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<DebugInformationFormat />
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<AdditionalIncludeDirectories>.;$(QTDIR)\include;.\GeneratedFiles\$(ConfigurationName);$(QTDIR)\include\QtCore;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<OutputFile>$(OutDir)\$(ProjectName).exe</OutputFile>
<AdditionalLibraryDirectories>$(QTDIR)\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateDebugInformation>false</GenerateDebugInformation>
<AdditionalDependencies>qtmain.lib;Qt5Core.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
<ProjectExtensions>
<VisualStudio>
<UserProperties MocDir=".\GeneratedFiles\$(ConfigurationName)" UicDir=".\GeneratedFiles" RccDir=".\GeneratedFiles" lupdateOptions="" lupdateOnBuild="0" lreleaseOptions="" Qt5Version_x0020_Win32="QtStatic" MocOptions="" />
</VisualStudio>
</ProjectExtensions>
</Project>

View file

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;cxx;c;def</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{D9D6E242-F8AF-46E4-B9FD-80ECBC20BA3E}</UniqueIdentifier>
<Extensions>qrc;*</Extensions>
<ParseFiles>false</ParseFiles>
</Filter>
<Filter Include="Generated Files">
<UniqueIdentifier>{71ED8ED8-ACB9-4CE9-BBE1-E00B30144E11}</UniqueIdentifier>
<Extensions>moc;h;cpp</Extensions>
<SourceControlFiles>False</SourceControlFiles>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\..\SourceFiles\codegen\style\main.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>