mirror of
https://github.com/vale981/tdesktop
synced 2025-03-06 10:11:41 -05:00
Merged with master.
This commit is contained in:
commit
fa4137418a
35 changed files with 771 additions and 396 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -7,6 +7,7 @@
|
|||
/Telegram/SourceFiles/art/sprite_125x.png
|
||||
/Telegram/SourceFiles/art/sprite_150x.png
|
||||
/Telegram/*.user
|
||||
*.vcxproj.user
|
||||
*.suo
|
||||
*.sdf
|
||||
*.opensdf
|
||||
|
|
|
@ -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
|
|
@ -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
25
.travis/check.sh
Executable 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
40
.travis/common.sh
Executable 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:$*"
|
||||
}
|
21
Telegram.sln
21
Telegram.sln
|
@ -1,7 +1,7 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 2013
|
||||
VisualStudioVersion = 12.0.30501.0
|
||||
# Visual Studio 14
|
||||
VisualStudioVersion = 14.0.24720.0
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Telegram", "Telegram\Telegram.vcxproj", "{B12702AD-ABFB-343A-A199-8E24837244A3}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
|
@ -18,10 +18,12 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Updater", "Telegram\Updater
|
|||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MetaLang", "Telegram\MetaLang.vcxproj", "{E417CAA4-259B-4C99-88E3-805F1300E8EB}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{2F863EAD-33C9-4014-A573-93F085BA9CB1}"
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "codegen", "codegen", "{2F863EAD-33C9-4014-A573-93F085BA9CB1}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Packer", "Telegram\Packer.vcxproj", "{56A9A4B2-21E5-4360-AFA8-85B43AC43B08}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "codegen_style", "Telegram\build\vc\codegen_style\codegen_style.vcxproj", "{E4DF8176-4DEF-4859-962F-B497E3E7A323}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Win32 = Debug|Win32
|
||||
|
@ -82,8 +84,21 @@ Global
|
|||
{56A9A4B2-21E5-4360-AFA8-85B43AC43B08}.Deploy|x64.ActiveCfg = Release|Win32
|
||||
{56A9A4B2-21E5-4360-AFA8-85B43AC43B08}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{56A9A4B2-21E5-4360-AFA8-85B43AC43B08}.Release|x64.ActiveCfg = Release|Win32
|
||||
{E4DF8176-4DEF-4859-962F-B497E3E7A323}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{E4DF8176-4DEF-4859-962F-B497E3E7A323}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{E4DF8176-4DEF-4859-962F-B497E3E7A323}.Debug|x64.ActiveCfg = Debug|Win32
|
||||
{E4DF8176-4DEF-4859-962F-B497E3E7A323}.Deploy|Win32.ActiveCfg = Debug|Win32
|
||||
{E4DF8176-4DEF-4859-962F-B497E3E7A323}.Deploy|Win32.Build.0 = Debug|Win32
|
||||
{E4DF8176-4DEF-4859-962F-B497E3E7A323}.Deploy|x64.ActiveCfg = Release|Win32
|
||||
{E4DF8176-4DEF-4859-962F-B497E3E7A323}.Deploy|x64.Build.0 = Release|Win32
|
||||
{E4DF8176-4DEF-4859-962F-B497E3E7A323}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{E4DF8176-4DEF-4859-962F-B497E3E7A323}.Release|Win32.Build.0 = Release|Win32
|
||||
{E4DF8176-4DEF-4859-962F-B497E3E7A323}.Release|x64.ActiveCfg = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{E4DF8176-4DEF-4859-962F-B497E3E7A323} = {2F863EAD-33C9-4014-A573-93F085BA9CB1}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -56,7 +56,6 @@ namespace App {
|
|||
ApiWrap *api();
|
||||
|
||||
void logOut();
|
||||
bool loggedOut();
|
||||
|
||||
QString formatPhone(QString phone);
|
||||
|
||||
|
|
3
Telegram/SourceFiles/codegen/style/main.cpp
Normal file
3
Telegram/SourceFiles/codegen/style/main.cpp
Normal file
|
@ -0,0 +1,3 @@
|
|||
int main(int argc, char *argv[]) {
|
||||
return 0;
|
||||
}
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -120,6 +120,12 @@ namespace App {
|
|||
}
|
||||
}
|
||||
|
||||
void logOutDelayed() {
|
||||
if (Window *w = App::wnd()) {
|
||||
QMetaObject::invokeMethod(w, "onLogoutSure", Qt::QueuedConnection);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace Ui {
|
||||
|
|
|
@ -38,6 +38,9 @@ namespace App {
|
|||
void showSettings();
|
||||
|
||||
void activateClickHandler(ClickHandlerPtr handler, Qt::MouseButton button);
|
||||
|
||||
void logOutDelayed();
|
||||
|
||||
};
|
||||
|
||||
namespace Ui {
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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]);
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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 = "";
|
||||
|
|
|
@ -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
|
||||
|
|
91
Telegram/build/vc/codegen_style/codegen_style.vcxproj
Normal file
91
Telegram/build/vc/codegen_style/codegen_style.vcxproj
Normal 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>
|
|
@ -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>
|
Loading…
Add table
Reference in a new issue