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_150x.png
/Telegram/*.user
*.vcxproj.user
*.suo
*.sdf
*.opensdf

View file

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

View file

@ -10,23 +10,6 @@ run() {
check
}
# set colors
RCol='\e[0m' # Text Reset
# Regular Bold Underline High Intensity BoldHigh Intens Background High Intensity Backgrounds
Bla='\e[0;30m'; BBla='\e[1;30m'; UBla='\e[4;30m'; IBla='\e[0;90m'; BIBla='\e[1;90m'; On_Bla='\e[40m'; On_IBla='\e[0;100m';
Red='\e[0;31m'; BRed='\e[1;31m'; URed='\e[4;31m'; IRed='\e[0;91m'; BIRed='\e[1;91m'; On_Red='\e[41m'; On_IRed='\e[0;101m';
Gre='\e[0;32m'; BGre='\e[1;32m'; UGre='\e[4;32m'; IGre='\e[0;92m'; BIGre='\e[1;92m'; On_Gre='\e[42m'; On_IGre='\e[0;102m';
Yel='\e[0;33m'; BYel='\e[1;33m'; UYel='\e[4;33m'; IYel='\e[0;93m'; BIYel='\e[1;93m'; On_Yel='\e[43m'; On_IYel='\e[0;103m';
Blu='\e[0;34m'; BBlu='\e[1;34m'; UBlu='\e[4;34m'; IBlu='\e[0;94m'; BIBlu='\e[1;94m'; On_Blu='\e[44m'; On_IBlu='\e[0;104m';
Pur='\e[0;35m'; BPur='\e[1;35m'; UPur='\e[4;35m'; IPur='\e[0;95m'; BIPur='\e[1;95m'; On_Pur='\e[45m'; On_IPur='\e[0;105m';
Cya='\e[0;36m'; BCya='\e[1;36m'; UCya='\e[4;36m'; ICya='\e[0;96m'; BICya='\e[1;96m'; On_Cya='\e[46m'; On_ICya='\e[0;106m';
Whi='\e[0;37m'; BWhi='\e[1;37m'; UWhi='\e[4;37m'; IWhi='\e[0;97m'; BIWhi='\e[1;97m'; On_Whi='\e[47m'; On_IWhi='\e[0;107m';
# Set variables
_qtver=5.5.1
srcdir=${PWD}
downloadLibs() {
travis_fold_start "download_libs"
# Move telegram project to subfolder
@ -172,28 +155,6 @@ check() {
fi
}
start_msg() {
echo -e "\n${Gre}$*${RCol}"
}
info_msg() {
echo -e "\n${Cya}$*${RCol}"
}
error_msg() {
echo -e "\n${BRed}$*${RCol}"
}
success_msg() {
echo -e "\n${BGre}$*${RCol}"
}
travis_fold_start() {
echo "travis_fold:start:$*"
}
travis_fold_end() {
echo "travis_fold:end:$*"
}
source ./.travis/common.sh
run

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

View file

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

View file

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

View file

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

View file

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

View file

@ -56,7 +56,6 @@ namespace App {
ApiWrap *api();
void logOut();
bool loggedOut();
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
static const int32 AppVersion = 9036;
static const wchar_t *AppVersionStr = L"0.9.36";
static const int32 AppVersion = 9039;
static const wchar_t *AppVersionStr = L"0.9.39";
static const bool DevVersion = true;
//#define BETA_VERSION (9034004ULL) // just comment this line to build public version

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -470,19 +470,64 @@ protected:
void clearOnDestroy();
HistoryItem *addNewToLastBlock(const MTPMessage &msg, NewMessageType type);
friend class HistoryBlock;
// this method just removes a block from the blocks list
// when the last item from this block was detached and
// calls the required previousItemChanged()
void removeBlock(HistoryBlock *block);
void clearBlocks(bool leaveItems);
HistoryItem *createItem(const MTPMessage &msg, bool applyServiceAction, bool detachExistingItem);
HistoryItem *createItemForwarded(MsgId id, MTPDmessage::Flags flags, QDateTime date, int32 from, HistoryMessage *msg);
HistoryItem *createItemDocument(MsgId id, MTPDmessage::Flags flags, int32 viaBotId, MsgId replyTo, QDateTime date, int32 from, DocumentData *doc, const QString &caption);
HistoryItem *createItemPhoto(MsgId id, MTPDmessage::Flags flags, int32 viaBotId, MsgId replyTo, QDateTime date, int32 from, PhotoData *photo, const QString &caption);
HistoryItem *addNewItem(HistoryItem *adding, bool newMsg);
HistoryItem *addNewInTheMiddle(HistoryItem *newItem, int32 blockIndex, int32 itemIndex);
// All this methods add a new item to the first or last block
// depending on if we are in isBuildingFronBlock() state.
// The last block is created on the go if it is needed.
// If the previous item is a message group the new group is
// not created but is just united with the previous one.
// create(HistoryItem *previous) should return a new HistoryGroup*
// unite(HistoryGroup *existing) should unite a new group with an existing
template <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:
enum Flag {
enum class Flag {
f_has_pending_resized_items = (1 << 0),
f_pending_resize = (1 << 1),
f_pending_resize = (1 << 1),
};
Q_DECLARE_FLAGS(Flags, Flag);
Q_DECL_CONSTEXPR friend inline QFlags<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;
}
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;
}
Q_DECL_CONSTEXPR friend inline QFlags<Flags::enum_type> operator~(Flags::enum_type f) noexcept {
return ~QFlags<Flags::enum_type>(f);
}
Flags _flags;
ChatListLinksMap _chatListLinks;
@ -497,28 +542,18 @@ private:
MediaOverviewIds overviewIds[OverviewCount];
int32 overviewCountData[OverviewCount]; // -1 - not loaded, 0 - all loaded, > 0 - count, but not all loaded
friend class HistoryBlock;
friend class ChannelHistory;
// A pointer to the block that is currently being built.
// We hold this pointer so we can destroy it while building
// and then create a new one if it is necessary.
struct BuildingBlock {
int expectedItemsCount = 0; // optimization for block->items.reserve() call
HistoryBlock *block = nullptr;
};
UniquePointer<BuildingBlock> _buildingFrontBlock;
// this method just removes a block from the blocks list
// when the last item from this block was detached and
// calls the required previousItemChanged()
void removeBlock(HistoryBlock *block);
void clearBlocks(bool leaveItems);
HistoryItem *createItem(const MTPMessage &msg, bool applyServiceAction, bool detachExistingItem);
HistoryItem *createItemForwarded(MsgId id, MTPDmessage::Flags flags, QDateTime date, int32 from, HistoryMessage *msg);
HistoryItem *createItemDocument(MsgId id, MTPDmessage::Flags flags, int32 viaBotId, MsgId replyTo, QDateTime date, int32 from, DocumentData *doc, const QString &caption);
HistoryItem *createItemPhoto(MsgId id, MTPDmessage::Flags flags, int32 viaBotId, MsgId replyTo, QDateTime date, int32 from, PhotoData *photo, const QString &caption);
HistoryItem *addItemToBlock(HistoryItem *item, HistoryBlock *block);
HistoryItem *addNewItem(HistoryItem *adding, bool newMsg);
HistoryItem *addMessageGroupAfterPrevToBlock(const MTPDmessageGroup &group, HistoryItem *prev, HistoryBlock *block);
HistoryItem *addNewInTheMiddle(HistoryItem *newItem, int32 blockIndex, int32 itemIndex);
HistoryBlock *pushBackNewBlock();
HistoryBlock *pushFrontNewBlock();
// Creates if necessary a new block for adding item.
// Depending on isBuildingFrontBlock() gets front or back block.
HistoryBlock *prepareBlockForAddingItem();
};
@ -952,6 +987,7 @@ enum HistoryCursorState {
enum InfoDisplayType {
InfoDisplayDefault,
InfoDisplayOverImage,
InfoDisplayOverBackground,
};
inline bool isImportantChannelMessage(MsgId id, MTPDmessage::Flags flags) { // client-side important msgs always has_views or has_from_id
@ -1232,7 +1268,9 @@ struct HistoryMessageDate : public BaseComponent<HistoryMessageDate> {
struct HistoryMessageUnreadBar : public BaseComponent<HistoryMessageUnreadBar> {
void init(int count);
int height() const;
static int height();
static int marginTop();
void paint(Painter &p, int y, int w) const;
QString _text;
@ -1695,8 +1733,11 @@ protected:
HistoryItem *previous() const {
if (_block && _indexInBlock >= 0) {
if (_indexInBlock > 0) return _block->items.at(_indexInBlock - 1);
if (_indexInBlock > 0) {
return _block->items.at(_indexInBlock - 1);
}
if (HistoryBlock *previousBlock = _block->previous()) {
t_assert(!previousBlock->items.isEmpty());
return previousBlock->items.back();
}
}

View file

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

View file

@ -864,8 +864,12 @@ private:
enum ScrollChangeType {
ScrollChangeNone,
// When we toggle a pinned message.
ScrollChangeAdd,
ScrollChangeOldHistoryHeight,
// When loading a history part while scrolling down.
ScrollChangeNoJumpToBottom,
};
struct ScrollChange {
ScrollChangeType type;
@ -873,6 +877,10 @@ private:
};
void updateListSize(bool initial = false, bool loadedDown = false, const ScrollChange &change = { ScrollChangeNone, 0 });
// Counts scrollTop for placing the scroll right at the unread
// messages bar, choosing from _history and _migrated unreadBar.
int unreadBarTop() const;
void saveGifDone(DocumentData *doc, const MTPBool &result);
void reportSpamDone(PeerData *peer, const MTPBool &result, mtpRequestId request);

View file

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

View file

@ -107,7 +107,13 @@ namespace SignalHandlers {
Status restart(); // can be only CantOpen or Started
void finish();
void setSelfUsername(const QString &username);
void setAssertionInfo(const QString &info);
void setCrashAnnotation(const std::string &key, const QString &value);
// Remembers value pointer and tries to add the value to the crash report.
// Attention! You should call clearCrashAnnotationRef(key) before destroying value.
void setCrashAnnotationRef(const std::string &key, const QString *valuePtr);
inline void clearCrashAnnotationRef(const std::string &key) {
setCrashAnnotationRef(key, nullptr);
}
}

View file

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

View file

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

View file

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

View file

@ -287,18 +287,20 @@ void NotifyWindow::startHiding() {
void NotifyWindow::mousePressEvent(QMouseEvent *e) {
if (!history) return;
PeerId peer = history->peer->id;
MsgId msgId = (!history->peer->isUser() && item && item->mentionsMe() && item->id > 0) ? item->id : ShowAtUnreadMsgId;
if (e->button() == Qt::RightButton) {
unlinkHistoryAndNotify();
} else if (history) {
} else {
App::wnd()->showFromTray();
if (App::passcoded()) {
App::wnd()->setInnerFocus();
App::wnd()->notifyClear();
} else {
App::wnd()->hideSettings();
Ui::showPeerHistory(peer, (!history->peer->isUser() && item && item->mentionsMe() && item->id > 0) ? item->id : ShowAtUnreadMsgId);
Ui::showPeerHistory(peer, msgId);
}
e->ignore();
}
@ -505,11 +507,8 @@ void Window::clearWidgets() {
settings = 0;
}
if (main) {
main->animStop_show();
main->hide();
main->deleteLater();
main->rpcClear();
main = 0;
delete main;
main = nullptr;
}
if (intro) {
intro->stop_show();
@ -691,7 +690,7 @@ void Window::setupMain(bool anim, const MTPUser *self) {
}
void Window::updateCounter() {
if (App::quitting()) return;
if (!Global::started() || App::quitting()) return;
psUpdateCounter();
title->updateCounter();
@ -1185,7 +1184,11 @@ void Window::onLogout() {
}
void Window::onLogoutSure() {
App::logOut();
if (MTP::authedId()) {
App::logOut();
} else {
setupIntro(true);
}
}
void Window::updateGlobalMenu() {
@ -1951,7 +1954,10 @@ PreLaunchWindow::PreLaunchWindow(QString title) : TWidget(0) {
tmp.setText(qsl("Tmp"));
_size = tmp.sizeHint().height();
setStyleSheet(qsl("QPushButton { padding: %1px %2px; background-color: #ffffff; border-radius: %3px; }\nQPushButton#confirm:hover, QPushButton#cancel:hover { background-color: #edf7ff; color: #2f9fea; }\nQPushButton#confirm { color: #2f9fea; }\nQPushButton#cancel { color: #aeaeae; }\nQLineEdit { border: 1px solid #e0e0e0; padding: 5px; }\nQLineEdit:focus { border: 2px solid #62c0f7; padding: 4px; }").arg(qFloor(_size / 2)).arg(qFloor(_size)).arg(qFloor(_size / 5)));
int paddingVertical = (_size / 2);
int paddingHorizontal = _size;
int borderRadius = (_size / 5);
setStyleSheet(qsl("QPushButton { padding: %1px %2px; background-color: #ffffff; border-radius: %3px; }\nQPushButton#confirm:hover, QPushButton#cancel:hover { background-color: #edf7ff; color: #2f9fea; }\nQPushButton#confirm { color: #2f9fea; }\nQPushButton#cancel { color: #aeaeae; }\nQLineEdit { border: 1px solid #e0e0e0; padding: 5px; }\nQLineEdit:focus { border: 2px solid #62c0f7; padding: 4px; }").arg(paddingVertical).arg(paddingHorizontal).arg(borderRadius));
if (!PreLaunchWindowInstance) {
PreLaunchWindowInstance = this;
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

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>