Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0a4038d061 | ||
|
|
2d5188b968 | ||
|
|
4bab7583ba | ||
|
|
b2f29b674d | ||
|
|
574f4a73cb | ||
|
|
05e3ddce0c | ||
|
|
3c101b0a50 | ||
|
|
e998bd0b3f | ||
|
|
251176df47 | ||
|
|
97c15865a5 | ||
|
|
9d4558de2b | ||
|
|
38f7f48c17 | ||
|
|
9534121676 | ||
|
|
10b76d921b |
@@ -9,7 +9,7 @@
|
||||
<Identity Name="TelegramMessengerLLP.TelegramDesktop"
|
||||
ProcessorArchitecture="ARCHITECTURE"
|
||||
Publisher="CN=536BC709-8EE1-4478-AF22-F0F0F26FF64A"
|
||||
Version="1.2.0.0" />
|
||||
Version="1.2.1.0" />
|
||||
<Properties>
|
||||
<DisplayName>Telegram Desktop</DisplayName>
|
||||
<PublisherDisplayName>Telegram Messenger LLP</PublisherDisplayName>
|
||||
|
||||
@@ -34,8 +34,8 @@ IDI_ICON1 ICON "..\\art\\icon256.ico"
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 1,2,0,0
|
||||
PRODUCTVERSION 1,2,0,0
|
||||
FILEVERSION 1,2,1,0
|
||||
PRODUCTVERSION 1,2,1,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
@@ -52,10 +52,10 @@ BEGIN
|
||||
BEGIN
|
||||
VALUE "CompanyName", "Telegram Messenger LLP"
|
||||
VALUE "FileDescription", "Telegram Desktop"
|
||||
VALUE "FileVersion", "1.2.0.0"
|
||||
VALUE "FileVersion", "1.2.1.0"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2014-2017"
|
||||
VALUE "ProductName", "Telegram Desktop"
|
||||
VALUE "ProductVersion", "1.2.0.0"
|
||||
VALUE "ProductVersion", "1.2.1.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
||||
@@ -25,8 +25,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 1,2,0,0
|
||||
PRODUCTVERSION 1,2,0,0
|
||||
FILEVERSION 1,2,1,0
|
||||
PRODUCTVERSION 1,2,1,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
@@ -43,10 +43,10 @@ BEGIN
|
||||
BEGIN
|
||||
VALUE "CompanyName", "Telegram Messenger LLP"
|
||||
VALUE "FileDescription", "Telegram Desktop Updater"
|
||||
VALUE "FileVersion", "1.2.0.0"
|
||||
VALUE "FileVersion", "1.2.1.0"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2014-2017"
|
||||
VALUE "ProductName", "Telegram Desktop"
|
||||
VALUE "ProductVersion", "1.2.0.0"
|
||||
VALUE "ProductVersion", "1.2.1.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
||||
@@ -22,7 +22,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||
|
||||
bool _debug = false;
|
||||
|
||||
wstring updaterName, updaterDir, updateTo, exeName;
|
||||
wstring updaterName, updaterDir, updateTo, exeName, customWorkingDir, customKeyFile;
|
||||
|
||||
bool equal(const wstring &a, const wstring &b) {
|
||||
return !_wcsicmp(a.c_str(), b.c_str());
|
||||
@@ -356,6 +356,7 @@ int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE prevInstance, LPWSTR cmdPara
|
||||
args = CommandLineToArgvW(GetCommandLine(), &argsCount);
|
||||
if (args) {
|
||||
for (int i = 1; i < argsCount; ++i) {
|
||||
writeLog(std::wstring(L"Argument: ") + args[i]);
|
||||
if (equal(args[i], L"-update")) {
|
||||
needupdate = true;
|
||||
} else if (equal(args[i], L"-autostart")) {
|
||||
@@ -368,17 +369,25 @@ int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE prevInstance, LPWSTR cmdPara
|
||||
} else if (equal(args[i], L"-testmode")) {
|
||||
testmode = true;
|
||||
} else if (equal(args[i], L"-writeprotected") && ++i < argsCount) {
|
||||
writeLog(std::wstring(L"Argument: ") + args[i]);
|
||||
writeprotected = true;
|
||||
updateTo = args[i];
|
||||
for (int i = 0, l = updateTo.size(); i < l; ++i) {
|
||||
if (updateTo[i] == L'/') {
|
||||
updateTo[i] = L'\\';
|
||||
for (int j = 0, l = updateTo.size(); j < l; ++j) {
|
||||
if (updateTo[j] == L'/') {
|
||||
updateTo[j] = L'\\';
|
||||
}
|
||||
}
|
||||
} else if (equal(args[i], L"-workdir") && ++i < argsCount) {
|
||||
writeLog(std::wstring(L"Argument: ") + args[i]);
|
||||
customWorkingDir = args[i];
|
||||
} else if (equal(args[i], L"-key") && ++i < argsCount) {
|
||||
writeLog(std::wstring(L"Argument: ") + args[i]);
|
||||
customKeyFile = args[i];
|
||||
} else if (equal(args[i], L"-exename") && ++i < argsCount) {
|
||||
writeLog(std::wstring(L"Argument: ") + args[i]);
|
||||
exeName = args[i];
|
||||
for (int i = 0, l = exeName.size(); i < l; ++i) {
|
||||
if (exeName[i] == L'/' || exeName[i] == L'\\') {
|
||||
for (int j = 0, l = exeName.size(); j < l; ++j) {
|
||||
if (exeName[j] == L'/' || exeName[j] == L'\\') {
|
||||
exeName = L"Telegram.exe";
|
||||
break;
|
||||
}
|
||||
@@ -391,6 +400,7 @@ int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE prevInstance, LPWSTR cmdPara
|
||||
if (needupdate) writeLog(L"Need to update!");
|
||||
if (autostart) writeLog(L"From autostart!");
|
||||
if (writeprotected) writeLog(L"Write Protected folder!");
|
||||
if (!customWorkingDir.empty()) writeLog(L"Will pass custom working dir: " + customWorkingDir);
|
||||
|
||||
updaterName = args[0];
|
||||
writeLog(L"Updater name is: " + updaterName);
|
||||
@@ -428,6 +438,13 @@ int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE prevInstance, LPWSTR cmdPara
|
||||
if (debug) targs += L" -debug";
|
||||
if (startintray) targs += L" -startintray";
|
||||
if (testmode) targs += L" -testmode";
|
||||
if (!customWorkingDir.empty()) {
|
||||
targs += L" -workdir \"" + customWorkingDir + L"\"";
|
||||
}
|
||||
if (!customKeyFile.empty()) {
|
||||
targs += L" -key \"" + customKeyFile + L"\"";
|
||||
}
|
||||
writeLog(L"Result arguments: " + targs);
|
||||
|
||||
bool executed = false;
|
||||
if (writeprotected) { // run un-elevated
|
||||
|
||||
@@ -344,9 +344,16 @@ string CurrentExecutablePath(int argc, char *argv[]) {
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
bool needupdate = true, autostart = false, debug = false, tosettings = false, startintray = false, testmode = false;
|
||||
bool needupdate = true;
|
||||
bool autostart = false;
|
||||
bool debug = false;
|
||||
bool tosettings = false;
|
||||
bool startintray = false;
|
||||
bool testmode = false;
|
||||
bool customWorkingDir = false;
|
||||
|
||||
char *key = 0, *crashreport = 0;
|
||||
char *key = 0;
|
||||
char *workdir = 0;
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
if (equal(argv[i], "-noupdate")) {
|
||||
needupdate = false;
|
||||
@@ -360,12 +367,12 @@ int main(int argc, char *argv[]) {
|
||||
testmode = true;
|
||||
} else if (equal(argv[i], "-tosettings")) {
|
||||
tosettings = true;
|
||||
} else if (equal(argv[i], "-workdir_custom")) {
|
||||
customWorkingDir = true;
|
||||
} else if (equal(argv[i], "-key") && ++i < argc) {
|
||||
key = argv[i];
|
||||
} else if (equal(argv[i], "-workpath") && ++i < argc) {
|
||||
workDir = argv[i];
|
||||
} else if (equal(argv[i], "-crashreport") && ++i < argc) {
|
||||
crashreport = argv[i];
|
||||
workDir = workdir = argv[i];
|
||||
} else if (equal(argv[i], "-exename") && ++i < argc) {
|
||||
exeName = argv[i];
|
||||
} else if (equal(argv[i], "-exepath") && ++i < argc) {
|
||||
@@ -401,6 +408,8 @@ int main(int argc, char *argv[]) {
|
||||
}
|
||||
if (needupdate) {
|
||||
if (workDir.empty()) { // old app launched, update prepared in tupdates/ready (not in tupdates/temp)
|
||||
customWorkingDir = false;
|
||||
|
||||
writeLog("No workdir, trying to figure it out");
|
||||
struct passwd *pw = getpwuid(getuid());
|
||||
if (pw && pw->pw_dir && strlen(pw->pw_dir)) {
|
||||
@@ -446,22 +455,30 @@ int main(int argc, char *argv[]) {
|
||||
string fullBinaryPath = exePath + exeName;
|
||||
strcpy(path, fullBinaryPath.c_str());
|
||||
|
||||
char *args[MaxArgsCount] = {0}, p_noupdate[] = "-noupdate", p_autostart[] = "-autostart", p_debug[] = "-debug", p_tosettings[] = "-tosettings", p_key[] = "-key", p_startintray[] = "-startintray", p_testmode[] = "-testmode";
|
||||
char *args[MaxArgsCount] = { 0 };
|
||||
char p_noupdate[] = "-noupdate";
|
||||
char p_autostart[] = "-autostart";
|
||||
char p_debug[] = "-debug";
|
||||
char p_tosettings[] = "-tosettings";
|
||||
char p_key[] = "-key";
|
||||
char p_startintray[] = "-startintray";
|
||||
char p_testmode[] = "-testmode";
|
||||
char p_workdir[] = "-workdir";
|
||||
int argIndex = 0;
|
||||
args[argIndex++] = path;
|
||||
if (crashreport) {
|
||||
args[argIndex++] = crashreport;
|
||||
} else {
|
||||
args[argIndex++] = p_noupdate;
|
||||
if (autostart) args[argIndex++] = p_autostart;
|
||||
if (debug) args[argIndex++] = p_debug;
|
||||
if (startintray) args[argIndex++] = p_startintray;
|
||||
if (testmode) args[argIndex++] = p_testmode;
|
||||
if (tosettings) args[argIndex++] = p_tosettings;
|
||||
if (key) {
|
||||
args[argIndex++] = p_key;
|
||||
args[argIndex++] = key;
|
||||
}
|
||||
args[argIndex++] = p_noupdate;
|
||||
if (autostart) args[argIndex++] = p_autostart;
|
||||
if (debug) args[argIndex++] = p_debug;
|
||||
if (startintray) args[argIndex++] = p_startintray;
|
||||
if (testmode) args[argIndex++] = p_testmode;
|
||||
if (tosettings) args[argIndex++] = p_tosettings;
|
||||
if (key) {
|
||||
args[argIndex++] = p_key;
|
||||
args[argIndex++] = key;
|
||||
}
|
||||
if (customWorkingDir && workdir) {
|
||||
args[argIndex++] = p_workdir;
|
||||
args[argIndex++] = workdir;
|
||||
}
|
||||
pid_t pid = fork();
|
||||
switch (pid) {
|
||||
|
||||
@@ -23,7 +23,6 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||
NSString *appName = @"Telegram.app";
|
||||
NSString *appDir = nil;
|
||||
NSString *workDir = nil;
|
||||
NSString *crashReportArg = nil;
|
||||
|
||||
#ifdef _DEBUG
|
||||
BOOL _debug = YES;
|
||||
@@ -90,6 +89,7 @@ int main(int argc, const char * argv[]) {
|
||||
openLog();
|
||||
pid_t procId = 0;
|
||||
BOOL update = YES, toSettings = NO, autoStart = NO, startInTray = NO, testMode = NO;
|
||||
BOOL customWorkingDir = NO;
|
||||
NSString *key = nil;
|
||||
for (int i = 0; i < argc; ++i) {
|
||||
if ([@"-workpath" isEqualToString:[NSString stringWithUTF8String:argv[i]]]) {
|
||||
@@ -102,10 +102,6 @@ int main(int argc, const char * argv[]) {
|
||||
[formatter setNumberStyle:NSNumberFormatterDecimalStyle];
|
||||
procId = [[formatter numberFromString:[NSString stringWithUTF8String:argv[i]]] intValue];
|
||||
}
|
||||
} else if ([@"-crashreport" isEqualToString:[NSString stringWithUTF8String:argv[i]]]) {
|
||||
if (++i < argc) {
|
||||
crashReportArg = [NSString stringWithUTF8String:argv[i]];
|
||||
}
|
||||
} else if ([@"-noupdate" isEqualToString:[NSString stringWithUTF8String:argv[i]]]) {
|
||||
update = NO;
|
||||
} else if ([@"-tosettings" isEqualToString:[NSString stringWithUTF8String:argv[i]]]) {
|
||||
@@ -118,11 +114,16 @@ int main(int argc, const char * argv[]) {
|
||||
startInTray = YES;
|
||||
} else if ([@"-testmode" isEqualToString:[NSString stringWithUTF8String:argv[i]]]) {
|
||||
testMode = YES;
|
||||
} else if ([@"-workdir_custom" isEqualToString:[NSString stringWithUTF8String:argv[i]]]) {
|
||||
customWorkingDir = YES;
|
||||
} else if ([@"-key" isEqualToString:[NSString stringWithUTF8String:argv[i]]]) {
|
||||
if (++i < argc) key = [NSString stringWithUTF8String:argv[i]];
|
||||
}
|
||||
}
|
||||
if (!workDir) workDir = appDir;
|
||||
if (!workDir) {
|
||||
workDir = appDir;
|
||||
customWorkingDir = NO;
|
||||
}
|
||||
openLog();
|
||||
NSMutableArray *argsArr = [[NSMutableArray alloc] initWithCapacity:argc];
|
||||
for (int i = 0; i < argc; ++i) {
|
||||
@@ -242,17 +243,19 @@ int main(int argc, const char * argv[]) {
|
||||
}
|
||||
|
||||
NSString *appPath = [[NSArray arrayWithObjects:appDir, appRealName, nil] componentsJoinedByString:@""];
|
||||
NSMutableArray *args = [[NSMutableArray alloc] initWithObjects: crashReportArg ? crashReportArg : @"-noupdate", nil];
|
||||
if (!crashReportArg) {
|
||||
if (toSettings) [args addObject:@"-tosettings"];
|
||||
if (_debug) [args addObject:@"-debug"];
|
||||
if (startInTray) [args addObject:@"-startintray"];
|
||||
if (testMode) [args addObject:@"-testmode"];
|
||||
if (autoStart) [args addObject:@"-autostart"];
|
||||
if (key) {
|
||||
[args addObject:@"-key"];
|
||||
[args addObject:key];
|
||||
}
|
||||
NSMutableArray *args = [[NSMutableArray alloc] initWithObjects: @"-noupdate", nil];
|
||||
if (toSettings) [args addObject:@"-tosettings"];
|
||||
if (_debug) [args addObject:@"-debug"];
|
||||
if (startInTray) [args addObject:@"-startintray"];
|
||||
if (testMode) [args addObject:@"-testmode"];
|
||||
if (autoStart) [args addObject:@"-autostart"];
|
||||
if (key) {
|
||||
[args addObject:@"-key"];
|
||||
[args addObject:key];
|
||||
}
|
||||
if (customWorkingDir) {
|
||||
[args addObject:@"-workdir"];
|
||||
[args addObject:workDir];
|
||||
}
|
||||
writeLog([[NSArray arrayWithObjects:@"Running application '", appPath, @"' with args '", [args componentsJoinedByString:@"' '"], @"'..", nil] componentsJoinedByString:@""]);
|
||||
NSError *error = nil;
|
||||
|
||||
@@ -946,7 +946,7 @@ void ApiWrap::saveStickerSets(const Stickers::Order &localOrder, const Stickers:
|
||||
request(base::take(_stickersClearRecentRequestId)).cancel();
|
||||
|
||||
auto writeInstalled = true, writeRecent = false, writeCloudRecent = false, writeFaved = false, writeArchived = false;
|
||||
auto &recent = cGetRecentStickers();
|
||||
auto &recent = Stickers::GetRecentPack();
|
||||
auto &sets = Auth().data().stickerSetsRef();
|
||||
|
||||
_stickersOrder = localOrder;
|
||||
|
||||
@@ -46,6 +46,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||
#include "numbers.h"
|
||||
#include "observer_peer.h"
|
||||
#include "auth_session.h"
|
||||
#include "core/crash_reports.h"
|
||||
#include "storage/storage_facade.h"
|
||||
#include "storage/storage_shared_media.h"
|
||||
#include "window/themes/window_theme.h"
|
||||
@@ -472,7 +473,7 @@ namespace {
|
||||
QString pname = (showPhoneChanged || phoneChanged || nameChanged) ? ((showPhone && !phone.isEmpty()) ? formatPhone(phone) : QString()) : data->nameOrPhone;
|
||||
|
||||
if (!minimal && d.is_self() && uname != data->username) {
|
||||
SignalHandlers::setCrashAnnotation("Username", uname);
|
||||
CrashReports::SetAnnotation("Username", uname);
|
||||
}
|
||||
data->setName(fname, lname, pname, uname);
|
||||
if (d.has_photo()) {
|
||||
|
||||
@@ -26,8 +26,10 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||
#include "storage/localstorage.h"
|
||||
#include "autoupdater.h"
|
||||
#include "window/notifications_manager.h"
|
||||
#include "core/crash_reports.h"
|
||||
#include "messenger.h"
|
||||
#include "base/timer.h"
|
||||
#include "core/crash_report_window.h"
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -71,8 +73,13 @@ QString _escapeFrom7bit(const QString &str) {
|
||||
|
||||
} // namespace
|
||||
|
||||
Application::Application(int &argc, char **argv) : QApplication(argc, argv) {
|
||||
QByteArray d(QFile::encodeName(QDir(cWorkingDir()).absolutePath()));
|
||||
Application::Application(
|
||||
not_null<Core::Launcher*> launcher,
|
||||
int &argc,
|
||||
char **argv)
|
||||
: QApplication(argc, argv)
|
||||
, _launcher(launcher) {
|
||||
const auto d = QFile::encodeName(QDir(cWorkingDir()).absolutePath());
|
||||
char h[33] = { 0 };
|
||||
hashMd5Hex(d.constData(), d.size(), h);
|
||||
#ifndef OS_MAC_STORE
|
||||
@@ -206,12 +213,12 @@ void Application::singleInstanceChecked() {
|
||||
if (!Logs::started() || (!cManyInstance() && !Logs::instanceChecked())) {
|
||||
new NotStartedWindow();
|
||||
} else {
|
||||
SignalHandlers::Status status = SignalHandlers::start();
|
||||
if (status == SignalHandlers::CantOpen) {
|
||||
const auto status = CrashReports::Start();
|
||||
if (status == CrashReports::CantOpen) {
|
||||
new NotStartedWindow();
|
||||
} else if (status == SignalHandlers::LastCrashed) {
|
||||
} else if (status == CrashReports::LastCrashed) {
|
||||
if (Sandbox::LastCrashDump().isEmpty()) { // don't handle bad closing for now
|
||||
if (SignalHandlers::restart() == SignalHandlers::CantOpen) {
|
||||
if (CrashReports::Restart() == CrashReports::CantOpen) {
|
||||
new NotStartedWindow();
|
||||
} else {
|
||||
Sandbox::launch();
|
||||
@@ -313,7 +320,7 @@ void Application::startApplication() {
|
||||
|
||||
void Application::createMessenger() {
|
||||
Expects(!App::quitting());
|
||||
_messengerInstance = std::make_unique<Messenger>();
|
||||
_messengerInstance = std::make_unique<Messenger>(_launcher);
|
||||
}
|
||||
|
||||
void Application::closeApplication() {
|
||||
|
||||
@@ -21,11 +21,16 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||
#pragma once
|
||||
|
||||
class UpdateChecker;
|
||||
|
||||
namespace Core {
|
||||
class Launcher;
|
||||
} // namespace Core
|
||||
|
||||
class Application : public QApplication {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
Application(int &argc, char **argv);
|
||||
Application(not_null<Core::Launcher*> launcher, int &argc, char **argv);
|
||||
|
||||
bool event(QEvent *e) override;
|
||||
|
||||
@@ -55,6 +60,7 @@ private:
|
||||
typedef QPair<QLocalSocket*, QByteArray> LocalClient;
|
||||
typedef QList<LocalClient> LocalClients;
|
||||
|
||||
not_null<Core::Launcher*> _launcher;
|
||||
std::unique_ptr<Messenger> _messengerInstance;
|
||||
|
||||
QString _localServerName, _localSocketReadData;
|
||||
|
||||
@@ -30,6 +30,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||
#include "ui/widgets/labels.h"
|
||||
#include "styles/style_boxes.h"
|
||||
#include "platform/platform_file_utilities.h"
|
||||
#include "core/click_handler_types.h"
|
||||
|
||||
AboutBox::AboutBox(QWidget *parent)
|
||||
: _version(this, lng_about_version(lt_version, QString::fromLatin1(AppVersionStr.c_str()) + (cAlphaVersion() ? " alpha" : "") + (cBetaVersion() ? qsl(" beta %1").arg(cBetaVersion()) : QString())), st::aboutVersionLink)
|
||||
@@ -43,7 +44,18 @@ void AboutBox::prepare() {
|
||||
|
||||
addButton(langFactory(lng_close), [this] { closeBox(); });
|
||||
|
||||
const auto linkHook = [](const ClickHandlerPtr &link, auto button) {
|
||||
if (const auto url = dynamic_cast<UrlClickHandler*>(link.data())) {
|
||||
url->UrlClickHandler::onClick(button);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
_text3->setRichText(lng_about_text_3(lt_faq_open, qsl("[a href=\"%1\"]").arg(telegramFaqLink()), lt_faq_close, qsl("[/a]")));
|
||||
_text1->setClickHandlerHook(linkHook);
|
||||
_text2->setClickHandlerHook(linkHook);
|
||||
_text3->setClickHandlerHook(linkHook);
|
||||
|
||||
_version->setClickedCallback([this] { showVersionHistory(); });
|
||||
|
||||
|
||||
@@ -715,10 +715,10 @@ public:
|
||||
}
|
||||
void peerListSortRows(
|
||||
base::lambda<bool(const PeerListRow &a, const PeerListRow &b)> compare) override {
|
||||
_content->reorderRows([compare = std::move(compare)](
|
||||
_content->reorderRows([&](
|
||||
auto &&begin,
|
||||
auto &&end) {
|
||||
std::sort(begin, end, [&compare](auto &&a, auto &&b) {
|
||||
std::sort(begin, end, [&](auto &&a, auto &&b) {
|
||||
return compare(*a, *b);
|
||||
});
|
||||
});
|
||||
@@ -726,10 +726,10 @@ public:
|
||||
int peerListPartitionRows(
|
||||
base::lambda<bool(const PeerListRow &a)> border) override {
|
||||
auto result = 0;
|
||||
_content->reorderRows([border = std::move(border), &result](
|
||||
_content->reorderRows([&](
|
||||
auto &&begin,
|
||||
auto &&end) {
|
||||
auto edge = std::stable_partition(begin, end, [&border](
|
||||
auto edge = std::stable_partition(begin, end, [&](
|
||||
auto &¤t) {
|
||||
return border(*current);
|
||||
});
|
||||
|
||||
@@ -1551,13 +1551,13 @@ int StickersBox::Inner::fillSetCount(const Stickers::Set &set) const {
|
||||
auto customIt = Auth().data().stickerSets().constFind(Stickers::CustomSetId);
|
||||
if (customIt != Auth().data().stickerSets().cend()) {
|
||||
added = customIt->stickers.size();
|
||||
for_const (auto &sticker, cGetRecentStickers()) {
|
||||
for_const (auto &sticker, Stickers::GetRecentPack()) {
|
||||
if (customIt->stickers.indexOf(sticker.first) < 0) {
|
||||
++added;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
added = cGetRecentStickers().size();
|
||||
added = Stickers::GetRecentPack().size();
|
||||
}
|
||||
}
|
||||
return result + added;
|
||||
|
||||
@@ -347,7 +347,7 @@ void SetsReceived(const QVector<MTPStickerSet> &data, int32 hash) {
|
||||
}
|
||||
}
|
||||
auto writeRecent = false;
|
||||
auto &recent = cGetRecentStickers();
|
||||
auto &recent = GetRecentPack();
|
||||
for (auto it = sets.begin(), e = sets.end(); it != e;) {
|
||||
bool installed = (it->flags & MTPDstickerSet::Flag::f_installed);
|
||||
bool featured = (it->flags & MTPDstickerSet_ClientFlag::f_featured);
|
||||
@@ -449,7 +449,7 @@ void SpecialSetReceived(uint64 setId, const QString &setTitle, const QVector<MTP
|
||||
}
|
||||
|
||||
auto writeRecent = false;
|
||||
auto &recent = cGetRecentStickers();
|
||||
auto &recent = GetRecentPack();
|
||||
for (auto i = recent.begin(); i != recent.cend();) {
|
||||
if (it->stickers.indexOf(i->first) >= 0 && pack.indexOf(i->first) < 0) {
|
||||
i = recent.erase(i);
|
||||
@@ -748,7 +748,7 @@ Set *FeedSetFull(const MTPmessages_StickerSet &data) {
|
||||
}
|
||||
|
||||
auto writeRecent = false;
|
||||
auto &recent = cGetRecentStickers();
|
||||
auto &recent = GetRecentPack();
|
||||
for (auto i = recent.begin(); i != recent.cend();) {
|
||||
if (set->stickers.indexOf(i->first) >= 0 && pack.indexOf(i->first) < 0) {
|
||||
i = recent.erase(i);
|
||||
@@ -816,4 +816,56 @@ QString GetSetTitle(const MTPDstickerSet &s) {
|
||||
return title;
|
||||
}
|
||||
|
||||
RecentStickerPack &GetRecentPack() {
|
||||
if (cRecentStickers().isEmpty() && !cRecentStickersPreload().isEmpty()) {
|
||||
const auto p = cRecentStickersPreload();
|
||||
cSetRecentStickersPreload(RecentStickerPreload());
|
||||
|
||||
auto &recent = cRefRecentStickers();
|
||||
recent.reserve(p.size());
|
||||
for (const auto &preloaded : p) {
|
||||
const auto document = App::document(preloaded.first);
|
||||
if (!document || !document->sticker()) continue;
|
||||
|
||||
recent.push_back(qMakePair(document, preloaded.second));
|
||||
}
|
||||
}
|
||||
return cRefRecentStickers();
|
||||
}
|
||||
|
||||
void IncrementRecentHashtag(RecentHashtagPack &recent, const QString &tag) {
|
||||
auto i = recent.begin(), e = recent.end();
|
||||
for (; i != e; ++i) {
|
||||
if (i->first == tag) {
|
||||
++i->second;
|
||||
if (qAbs(i->second) > 0x4000) {
|
||||
for (auto j = recent.begin(); j != e; ++j) {
|
||||
if (j->second > 1) {
|
||||
j->second /= 2;
|
||||
} else if (j->second > 0) {
|
||||
j->second = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (; i != recent.begin(); --i) {
|
||||
if (qAbs((i - 1)->second) > qAbs(i->second)) {
|
||||
break;
|
||||
}
|
||||
qSwap(*i, *(i - 1));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == e) {
|
||||
while (recent.size() >= 64) recent.pop_back();
|
||||
recent.push_back(qMakePair(tag, 1));
|
||||
for (i = recent.end() - 1; i != recent.begin(); --i) {
|
||||
if ((i - 1)->second > i->second) {
|
||||
break;
|
||||
}
|
||||
qSwap(*i, *(i - 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Stickers
|
||||
|
||||
@@ -85,4 +85,8 @@ Set *FeedSetFull(const MTPmessages_StickerSet &data);
|
||||
|
||||
QString GetSetTitle(const MTPDstickerSet &s);
|
||||
|
||||
RecentStickerPack &GetRecentPack();
|
||||
|
||||
void IncrementRecentHashtag(RecentHashtagPack &recent, const QString &tag);
|
||||
|
||||
} // namespace Stickers
|
||||
|
||||
@@ -1090,7 +1090,7 @@ void StickersListWidget::removeRecentSticker(int section, int index) {
|
||||
clearSelection();
|
||||
bool refresh = false;
|
||||
auto sticker = _mySets[section].pack[index];
|
||||
auto &recent = cGetRecentStickers();
|
||||
auto &recent = Stickers::GetRecentPack();
|
||||
for (int32 i = 0, l = recent.size(); i < l; ++i) {
|
||||
if (recent.at(i).first == sticker) {
|
||||
recent.removeAt(i);
|
||||
@@ -1302,7 +1302,7 @@ void StickersListWidget::refreshRecentStickers(bool performResize) {
|
||||
_custom.clear();
|
||||
clearSelection();
|
||||
auto &sets = Auth().data().stickerSets();
|
||||
auto &recent = cGetRecentStickers();
|
||||
auto &recent = Stickers::GetRecentPack();
|
||||
auto customIt = sets.constFind(Stickers::CustomSetId);
|
||||
auto cloudIt = sets.constFind(Stickers::CloudRecentSetId);
|
||||
|
||||
@@ -1773,7 +1773,7 @@ void StickersListWidget::removeSet(uint64 setId) {
|
||||
request(MTPmessages_UninstallStickerSet(MTP_inputStickerSetShortName(MTP_string(it->shortName)))).send();
|
||||
}
|
||||
auto writeRecent = false;
|
||||
auto &recent = cGetRecentStickers();
|
||||
auto &recent = Stickers::GetRecentPack();
|
||||
for (auto i = recent.begin(); i != recent.cend();) {
|
||||
if (it->stickers.indexOf(i->first) >= 0) {
|
||||
i = recent.erase(i);
|
||||
|
||||
@@ -143,7 +143,7 @@ void HiddenUrlClickHandler::doOpen(QString url) {
|
||||
Ui::show(Box<ConfirmBox>(lang(lng_open_this_link) + qsl("\n\n") + displayUrl, lang(lng_open_link), [urlText] {
|
||||
Ui::hideLayer();
|
||||
UrlClickHandler::doOpen(urlText);
|
||||
}));
|
||||
}), LayerOption::KeepOther);
|
||||
} else {
|
||||
UrlClickHandler::doOpen(urlText);
|
||||
}
|
||||
|
||||
1080
Telegram/SourceFiles/core/crash_report_window.cpp
Normal file
1080
Telegram/SourceFiles/core/crash_report_window.cpp
Normal file
File diff suppressed because it is too large
Load Diff
226
Telegram/SourceFiles/core/crash_report_window.h
Normal file
226
Telegram/SourceFiles/core/crash_report_window.h
Normal file
@@ -0,0 +1,226 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop version of Telegram messaging app, see https://telegram.org
|
||||
|
||||
Telegram Desktop is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
It is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
In addition, as a special exception, the copyright holders give permission
|
||||
to link the code of portions of this program with the OpenSSL library.
|
||||
|
||||
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||
Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
class PreLaunchWindow : public QWidget {
|
||||
public:
|
||||
PreLaunchWindow(QString title = QString());
|
||||
void activate();
|
||||
int basicSize() const {
|
||||
return _size;
|
||||
}
|
||||
~PreLaunchWindow();
|
||||
|
||||
static PreLaunchWindow *instance();
|
||||
|
||||
protected:
|
||||
|
||||
int _size;
|
||||
|
||||
};
|
||||
|
||||
class PreLaunchLabel : public QLabel {
|
||||
public:
|
||||
PreLaunchLabel(QWidget *parent);
|
||||
void setText(const QString &text);
|
||||
|
||||
};
|
||||
|
||||
class PreLaunchInput : public QLineEdit {
|
||||
public:
|
||||
PreLaunchInput(QWidget *parent, bool password = false);
|
||||
|
||||
};
|
||||
|
||||
class PreLaunchLog : public QTextEdit {
|
||||
public:
|
||||
PreLaunchLog(QWidget *parent);
|
||||
|
||||
};
|
||||
|
||||
class PreLaunchButton : public QPushButton {
|
||||
public:
|
||||
PreLaunchButton(QWidget *parent, bool confirm = true);
|
||||
void setText(const QString &text);
|
||||
|
||||
};
|
||||
|
||||
class PreLaunchCheckbox : public QCheckBox {
|
||||
public:
|
||||
PreLaunchCheckbox(QWidget *parent);
|
||||
void setText(const QString &text);
|
||||
|
||||
};
|
||||
|
||||
class NotStartedWindow : public PreLaunchWindow {
|
||||
public:
|
||||
NotStartedWindow();
|
||||
|
||||
protected:
|
||||
void closeEvent(QCloseEvent *e);
|
||||
void resizeEvent(QResizeEvent *e);
|
||||
|
||||
private:
|
||||
void updateControls();
|
||||
|
||||
PreLaunchLabel _label;
|
||||
PreLaunchLog _log;
|
||||
PreLaunchButton _close;
|
||||
|
||||
};
|
||||
|
||||
class LastCrashedWindow : public PreLaunchWindow {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
LastCrashedWindow();
|
||||
|
||||
public slots:
|
||||
void onViewReport();
|
||||
void onSaveReport();
|
||||
void onSendReport();
|
||||
void onGetApp();
|
||||
|
||||
void onNetworkSettings();
|
||||
void onNetworkSettingsSaved(QString host, quint32 port, QString username, QString password);
|
||||
void onContinue();
|
||||
|
||||
void onCheckingFinished();
|
||||
void onSendingError(QNetworkReply::NetworkError e);
|
||||
void onSendingFinished();
|
||||
void onSendingProgress(qint64 uploaded, qint64 total);
|
||||
|
||||
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
|
||||
void onUpdateRetry();
|
||||
void onUpdateSkip();
|
||||
|
||||
void onUpdateChecking();
|
||||
void onUpdateLatest();
|
||||
void onUpdateDownloading(qint64 ready, qint64 total);
|
||||
void onUpdateReady();
|
||||
void onUpdateFailed();
|
||||
#endif // !TDESKTOP_DISABLE_AUTOUPDATE
|
||||
|
||||
protected:
|
||||
void closeEvent(QCloseEvent *e);
|
||||
void resizeEvent(QResizeEvent *e);
|
||||
|
||||
private:
|
||||
QString minidumpFileName();
|
||||
void updateControls();
|
||||
|
||||
QString _host, _username, _password;
|
||||
quint32 _port;
|
||||
|
||||
PreLaunchLabel _label, _pleaseSendReport, _yourReportName, _minidump;
|
||||
PreLaunchLog _report;
|
||||
PreLaunchButton _send, _sendSkip, _networkSettings, _continue, _showReport, _saveReport, _getApp;
|
||||
PreLaunchCheckbox _includeUsername;
|
||||
|
||||
QString _minidumpName, _minidumpFull, _reportText;
|
||||
QString _reportUsername, _reportTextNoUsername;
|
||||
QByteArray getCrashReportRaw() const;
|
||||
|
||||
bool _reportShown, _reportSaved;
|
||||
|
||||
void excludeReportUsername();
|
||||
|
||||
enum SendingState {
|
||||
SendingNoReport,
|
||||
SendingUpdateCheck,
|
||||
SendingNone,
|
||||
SendingTooOld,
|
||||
SendingTooMany,
|
||||
SendingUnofficial,
|
||||
SendingProgress,
|
||||
SendingUploading,
|
||||
SendingFail,
|
||||
SendingDone,
|
||||
};
|
||||
SendingState _sendingState;
|
||||
|
||||
PreLaunchLabel _updating;
|
||||
qint64 _sendingProgress, _sendingTotal;
|
||||
|
||||
QNetworkAccessManager _sendManager;
|
||||
QNetworkReply *_checkReply, *_sendReply;
|
||||
|
||||
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
|
||||
PreLaunchButton _updatingCheck, _updatingSkip;
|
||||
enum UpdatingState {
|
||||
UpdatingNone,
|
||||
UpdatingCheck,
|
||||
UpdatingLatest,
|
||||
UpdatingDownload,
|
||||
UpdatingFail,
|
||||
UpdatingReady
|
||||
};
|
||||
UpdatingState _updatingState;
|
||||
QString _newVersionDownload;
|
||||
|
||||
void setUpdatingState(UpdatingState state, bool force = false);
|
||||
void setDownloadProgress(qint64 ready, qint64 total);
|
||||
#endif // !TDESKTOP_DISABLE_AUTOUPDATE
|
||||
|
||||
QString getReportField(const QLatin1String &name, const QLatin1String &prefix);
|
||||
void addReportFieldPart(const QLatin1String &name, const QLatin1String &prefix, QHttpMultiPart *multipart);
|
||||
|
||||
};
|
||||
|
||||
class NetworkSettingsWindow : public PreLaunchWindow {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
NetworkSettingsWindow(QWidget *parent, QString host, quint32 port, QString username, QString password);
|
||||
|
||||
signals:
|
||||
void saved(QString host, quint32 port, QString username, QString password);
|
||||
|
||||
public slots:
|
||||
void onSave();
|
||||
|
||||
protected:
|
||||
void closeEvent(QCloseEvent *e);
|
||||
void resizeEvent(QResizeEvent *e);
|
||||
|
||||
private:
|
||||
void updateControls();
|
||||
|
||||
PreLaunchLabel _hostLabel, _portLabel, _usernameLabel, _passwordLabel;
|
||||
PreLaunchInput _hostInput, _portInput, _usernameInput, _passwordInput;
|
||||
PreLaunchButton _save, _cancel;
|
||||
|
||||
QWidget *_parent;
|
||||
|
||||
};
|
||||
|
||||
class ShowCrashReportWindow : public PreLaunchWindow {
|
||||
public:
|
||||
ShowCrashReportWindow(const QString &text);
|
||||
|
||||
protected:
|
||||
void resizeEvent(QResizeEvent *e);
|
||||
void closeEvent(QCloseEvent *e);
|
||||
|
||||
private:
|
||||
PreLaunchLog _log;
|
||||
|
||||
};
|
||||
580
Telegram/SourceFiles/core/crash_reports.cpp
Normal file
580
Telegram/SourceFiles/core/crash_reports.cpp
Normal file
@@ -0,0 +1,580 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop version of Telegram messaging app, see https://telegram.org
|
||||
|
||||
Telegram Desktop is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
It is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
In addition, as a special exception, the copyright holders give permission
|
||||
to link the code of portions of this program with the OpenSSL library.
|
||||
|
||||
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||
Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||
*/
|
||||
#include "core/crash_reports.h"
|
||||
|
||||
#include "platform/platform_specific.h"
|
||||
|
||||
#include <signal.h>
|
||||
#include <new>
|
||||
#include <mutex>
|
||||
|
||||
#ifndef TDESKTOP_DISABLE_CRASH_REPORTS
|
||||
|
||||
// see https://blog.inventic.eu/2012/08/qt-and-google-breakpad/
|
||||
#ifdef Q_OS_WIN
|
||||
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4091)
|
||||
#include "client/windows/handler/exception_handler.h"
|
||||
#pragma warning(pop)
|
||||
|
||||
#elif defined Q_OS_MAC // Q_OS_WIN
|
||||
|
||||
#include <execinfo.h>
|
||||
#include <signal.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <dlfcn.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef MAC_USE_BREAKPAD
|
||||
#include "client/mac/handler/exception_handler.h"
|
||||
#else // MAC_USE_BREAKPAD
|
||||
#include "client/crashpad_client.h"
|
||||
#endif // else for MAC_USE_BREAKPAD
|
||||
|
||||
#elif defined Q_OS_LINUX64 || defined Q_OS_LINUX32 // Q_OS_MAC
|
||||
|
||||
#include <execinfo.h>
|
||||
#include <signal.h>
|
||||
#include <sys/syscall.h>
|
||||
|
||||
#include "client/linux/handler/exception_handler.h"
|
||||
|
||||
#endif // Q_OS_LINUX64 || Q_OS_LINUX32
|
||||
|
||||
#endif // !TDESKTOP_DISABLE_CRASH_REPORTS
|
||||
|
||||
namespace CrashReports {
|
||||
namespace {
|
||||
|
||||
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 ReportPath;
|
||||
FILE *ReportFile = nullptr;
|
||||
int ReportFileNo = 0;
|
||||
char LaunchedDateTimeStr[32] = { 0 };
|
||||
char LaunchedBinaryName[256] = { 0 };
|
||||
|
||||
void SafeWriteChar(char ch) {
|
||||
fwrite(&ch, 1, 1, ReportFile);
|
||||
}
|
||||
|
||||
template <bool Unsigned, typename Type>
|
||||
struct writeNumberSignAndRemoveIt {
|
||||
static void call(Type &number) {
|
||||
if (number < 0) {
|
||||
SafeWriteChar('-');
|
||||
number = -number;
|
||||
}
|
||||
}
|
||||
};
|
||||
template <typename Type>
|
||||
struct writeNumberSignAndRemoveIt<true, Type> {
|
||||
static void call(Type &number) {
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Type>
|
||||
const dump &SafeWriteNumber(const dump &stream, Type number) {
|
||||
if (!ReportFile) return stream;
|
||||
|
||||
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);
|
||||
SafeWriteChar('0' + digit);
|
||||
number -= digit * upper;
|
||||
upper /= 10;
|
||||
}
|
||||
return stream;
|
||||
}
|
||||
|
||||
using ReservedMemoryChunk = std::array<gsl::byte, 1024 * 1024>;
|
||||
std::unique_ptr<ReservedMemoryChunk> ReservedMemory;
|
||||
|
||||
void InstallOperatorNewHandler() {
|
||||
ReservedMemory = std::make_unique<ReservedMemoryChunk>();
|
||||
std::set_new_handler([] {
|
||||
std::set_new_handler(nullptr);
|
||||
ReservedMemory.reset();
|
||||
Unexpected("Could not allocate!");
|
||||
});
|
||||
}
|
||||
|
||||
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];
|
||||
|
||||
void SignalHandler(int signum, siginfo_t *info, void *ucontext) {
|
||||
if (signum > 0) {
|
||||
sigaction(signum, &SIG_def[signum], 0);
|
||||
}
|
||||
|
||||
#else // Q_OS_MAC || Q_OS_LINUX32 || Q_OS_LINUX64
|
||||
void SignalHandler(int signum) {
|
||||
#endif // else for Q_OS_MAC || Q_OS_LINUX || Q_OS_LINUX64
|
||||
|
||||
const char* name = 0;
|
||||
switch (signum) {
|
||||
case SIGABRT: name = "SIGABRT"; break;
|
||||
case SIGSEGV: name = "SIGSEGV"; break;
|
||||
case SIGILL: name = "SIGILL"; break;
|
||||
case SIGFPE: name = "SIGFPE"; break;
|
||||
#ifndef Q_OS_WIN
|
||||
case SIGBUS: name = "SIGBUS"; break;
|
||||
case SIGSYS: name = "SIGSYS"; break;
|
||||
#endif // !Q_OS_WIN
|
||||
}
|
||||
|
||||
Qt::HANDLE thread = QThread::currentThreadId();
|
||||
if (thread == ReportingThreadId) return;
|
||||
|
||||
QMutexLocker lock(&ReportingMutex);
|
||||
ReportingThreadId = thread;
|
||||
|
||||
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";
|
||||
}
|
||||
psWriteDump();
|
||||
dump() << "\n";
|
||||
}
|
||||
if (name) {
|
||||
dump() << "Caught signal " << signum << " (" << name << ") in thread " << uint64(thread) << "\n";
|
||||
} else if (signum == -1) {
|
||||
dump() << "Google Breakpad caught a crash, minidump written in thread " << uint64(thread) << "\n";
|
||||
if (BreakpadDumpPath) {
|
||||
dump() << "Minidump: " << BreakpadDumpPath << "\n";
|
||||
} else if (BreakpadDumpPathW) {
|
||||
dump() << "Minidump: " << BreakpadDumpPathW << "\n";
|
||||
}
|
||||
} else {
|
||||
dump() << "Caught signal " << signum << " in thread " << uint64(thread) << "\n";
|
||||
}
|
||||
|
||||
// see https://github.com/benbjohnson/bandicoot
|
||||
#if defined Q_OS_MAC || defined Q_OS_LINUX32 || defined Q_OS_LINUX64
|
||||
ucontext_t *uc = (ucontext_t*)ucontext;
|
||||
|
||||
void *caller = 0;
|
||||
if (uc) {
|
||||
#if defined(__APPLE__) && !defined(MAC_OS_X_VERSION_10_6)
|
||||
/* OSX < 10.6 */
|
||||
#if defined(__x86_64__)
|
||||
caller = (void*)uc->uc_mcontext->__ss.__rip;
|
||||
#elif defined(__i386__)
|
||||
caller = (void*)uc->uc_mcontext->__ss.__eip;
|
||||
#else
|
||||
caller = (void*)uc->uc_mcontext->__ss.__srr0;
|
||||
#endif
|
||||
#elif defined(__APPLE__) && defined(MAC_OS_X_VERSION_10_6)
|
||||
/* OSX >= 10.6 */
|
||||
#if defined(_STRUCT_X86_THREAD_STATE64) && !defined(__i386__)
|
||||
caller = (void*)uc->uc_mcontext->__ss.__rip;
|
||||
#else
|
||||
caller = (void*)uc->uc_mcontext->__ss.__eip;
|
||||
#endif
|
||||
#elif defined(__linux__)
|
||||
/* Linux */
|
||||
#if defined(__i386__)
|
||||
caller = (void*)uc->uc_mcontext.gregs[14]; /* Linux 32 */
|
||||
#elif defined(__X86_64__) || defined(__x86_64__)
|
||||
caller = (void*)uc->uc_mcontext.gregs[16]; /* Linux 64 */
|
||||
#elif defined(__ia64__) /* Linux IA64 */
|
||||
caller = (void*)uc->uc_mcontext.sc_ip;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
void *addresses[132] = { 0 };
|
||||
size_t size = backtrace(addresses, 128);
|
||||
|
||||
/* overwrite sigaction with caller's address */
|
||||
if (caller) {
|
||||
for (int i = size; i > 1; --i) {
|
||||
addresses[i + 3] = addresses[i];
|
||||
}
|
||||
addresses[2] = (void*)0x1;
|
||||
addresses[3] = caller;
|
||||
addresses[4] = (void*)0x1;
|
||||
}
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
dump() << "\nBase image addresses:\n";
|
||||
for (size_t i = 0; i < size; ++i) {
|
||||
Dl_info info;
|
||||
dump() << i << " ";
|
||||
if (dladdr(addresses[i], &info)) {
|
||||
dump() << uint64(info.dli_fbase) << " (" << info.dli_fname << ")\n";
|
||||
} else {
|
||||
dump() << "_unknown_module_\n";
|
||||
}
|
||||
}
|
||||
#endif // Q_OS_MAC
|
||||
|
||||
dump() << "\nBacktrace:\n";
|
||||
|
||||
backtrace_symbols_fd(addresses, size, ReportFileNo);
|
||||
|
||||
#else // Q_OS_MAC || Q_OS_LINUX32 || Q_OS_LINUX64
|
||||
dump() << "\nBacktrace:\n";
|
||||
|
||||
psWriteStackTrace();
|
||||
#endif // else for Q_OS_MAC || Q_OS_LINUX32 || Q_OS_LINUX64
|
||||
|
||||
dump() << "\n";
|
||||
|
||||
ReportingThreadId = nullptr;
|
||||
}
|
||||
|
||||
bool SetSignalHandlers = true;
|
||||
bool CrashLogged = false;
|
||||
#if !defined Q_OS_MAC || defined MAC_USE_BREAKPAD
|
||||
google_breakpad::ExceptionHandler* BreakpadExceptionHandler = 0;
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
bool DumpCallback(const wchar_t* _dump_dir, const wchar_t* _minidump_id, void* context, EXCEPTION_POINTERS* exinfo, MDRawAssertionInfo* assertion, bool success)
|
||||
#elif defined Q_OS_MAC // Q_OS_WIN
|
||||
bool DumpCallback(const char* _dump_dir, const char* _minidump_id, void *context, bool success)
|
||||
#elif defined Q_OS_LINUX64 || defined Q_OS_LINUX32 // Q_OS_MAC
|
||||
bool DumpCallback(const google_breakpad::MinidumpDescriptor &md, void *context, bool success)
|
||||
#endif // Q_OS_LINUX64 || Q_OS_LINUX32
|
||||
{
|
||||
if (CrashLogged) return success;
|
||||
CrashLogged = true;
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
BreakpadDumpPathW = _minidump_id;
|
||||
SignalHandler(-1);
|
||||
#else // Q_OS_WIN
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
BreakpadDumpPath = _minidump_id;
|
||||
#else // Q_OS_MAC
|
||||
BreakpadDumpPath = md.path();
|
||||
#endif // else for Q_OS_MAC
|
||||
SignalHandler(-1, 0, 0);
|
||||
#endif // else for Q_OS_WIN
|
||||
return success;
|
||||
}
|
||||
#endif // !Q_OS_MAC || MAC_USE_BREAKPAD
|
||||
|
||||
#endif // !TDESKTOP_DISABLE_CRASH_REPORTS
|
||||
|
||||
} // namespace
|
||||
|
||||
void StartCatching() {
|
||||
#ifndef TDESKTOP_DISABLE_CRASH_REPORTS
|
||||
ProcessAnnotations["Binary"] = cExeName().toUtf8().constData();
|
||||
ProcessAnnotations["ApiId"] = QString::number(ApiId).toUtf8().constData();
|
||||
ProcessAnnotations["Version"] = (cBetaVersion() ? qsl("%1 beta").arg(cBetaVersion()) : (cAlphaVersion() ? qsl("%1 alpha") : qsl("%1")).arg(AppVersion)).toUtf8().constData();
|
||||
ProcessAnnotations["Launched"] = QDateTime::currentDateTime().toString("dd.MM.yyyy hh:mm:ss").toUtf8().constData();
|
||||
ProcessAnnotations["Platform"] = cPlatformString().toUtf8().constData();
|
||||
ProcessAnnotations["UserTag"] = QString::number(Sandbox::UserTag(), 16).toUtf8().constData();
|
||||
|
||||
QString dumpspath = cWorkingDir() + qsl("tdata/dumps");
|
||||
QDir().mkpath(dumpspath);
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
BreakpadExceptionHandler = new google_breakpad::ExceptionHandler(
|
||||
dumpspath.toStdWString(),
|
||||
google_breakpad::ExceptionHandler::FilterCallback(nullptr),
|
||||
DumpCallback,
|
||||
(void*)nullptr, // callback_context
|
||||
google_breakpad::ExceptionHandler::HANDLER_ALL,
|
||||
MINIDUMP_TYPE(MiniDumpNormal),
|
||||
// MINIDUMP_TYPE(MiniDumpWithFullMemory | MiniDumpWithHandleData | MiniDumpWithThreadInfo | MiniDumpWithProcessThreadData | MiniDumpWithFullMemoryInfo | MiniDumpWithUnloadedModules | MiniDumpWithFullAuxiliaryState | MiniDumpIgnoreInaccessibleMemory | MiniDumpWithTokenInformation),
|
||||
(const wchar_t*)nullptr, // pipe_name
|
||||
(const google_breakpad::CustomClientInfo*)nullptr
|
||||
);
|
||||
#elif defined Q_OS_MAC // Q_OS_WIN
|
||||
|
||||
#ifdef MAC_USE_BREAKPAD
|
||||
#ifndef _DEBUG
|
||||
BreakpadExceptionHandler = new google_breakpad::ExceptionHandler(
|
||||
QFile::encodeName(dumpspath).toStdString(),
|
||||
/*FilterCallback*/ 0,
|
||||
DumpCallback,
|
||||
/*context*/ 0,
|
||||
true,
|
||||
0
|
||||
);
|
||||
#endif // !_DEBUG
|
||||
SetSignalHandlers = false;
|
||||
#else // MAC_USE_BREAKPAD
|
||||
crashpad::CrashpadClient crashpad_client;
|
||||
std::string handler = (cExeDir() + cExeName() + qsl("/Contents/Helpers/crashpad_handler")).toUtf8().constData();
|
||||
std::string database = QFile::encodeName(dumpspath).constData();
|
||||
if (crashpad_client.StartHandler(base::FilePath(handler),
|
||||
base::FilePath(database),
|
||||
std::string(),
|
||||
ProcessAnnotations,
|
||||
std::vector<std::string>(),
|
||||
false)) {
|
||||
crashpad_client.UseHandler();
|
||||
}
|
||||
#endif // else for MAC_USE_BREAKPAD
|
||||
#elif defined Q_OS_LINUX64 || defined Q_OS_LINUX32
|
||||
BreakpadExceptionHandler = new google_breakpad::ExceptionHandler(
|
||||
google_breakpad::MinidumpDescriptor(QFile::encodeName(dumpspath).toStdString()),
|
||||
/*FilterCallback*/ 0,
|
||||
DumpCallback,
|
||||
/*context*/ 0,
|
||||
true,
|
||||
-1
|
||||
);
|
||||
#endif // Q_OS_LINUX64 || Q_OS_LINUX32
|
||||
#endif // !TDESKTOP_DISABLE_CRASH_REPORTS
|
||||
}
|
||||
|
||||
void FinishCatching() {
|
||||
#ifndef TDESKTOP_DISABLE_CRASH_REPORTS
|
||||
#if !defined Q_OS_MAC || defined MAC_USE_BREAKPAD
|
||||
|
||||
delete base::take(BreakpadExceptionHandler);
|
||||
|
||||
#endif // !Q_OS_MAC || MAC_USE_BREAKPAD
|
||||
#endif // !TDESKTOP_DISABLE_CRASH_REPORTS
|
||||
}
|
||||
|
||||
Status Start() {
|
||||
#ifndef TDESKTOP_DISABLE_CRASH_REPORTS
|
||||
ReportPath = cWorkingDir() + qsl("tdata/working");
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
FILE *f = nullptr;
|
||||
if (_wfopen_s(&f, ReportPath.toStdWString().c_str(), L"rb") != 0) {
|
||||
f = nullptr;
|
||||
} else {
|
||||
#else // !Q_OS_WIN
|
||||
if (FILE *f = fopen(QFile::encodeName(ReportPath).constData(), "rb")) {
|
||||
#endif // else for !Q_OS_WIN
|
||||
QByteArray lastdump;
|
||||
char buffer[256 * 1024] = { 0 };
|
||||
int32 read = fread(buffer, 1, 256 * 1024, f);
|
||||
if (read > 0) {
|
||||
lastdump.append(buffer, read);
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
Sandbox::SetLastCrashDump(lastdump);
|
||||
|
||||
LOG(("Opened '%1' for reading, the previous Telegram Desktop launch was not finished properly :( Crash log size: %2").arg(ReportPath).arg(lastdump.size()));
|
||||
|
||||
return LastCrashed;
|
||||
}
|
||||
|
||||
#endif // !TDESKTOP_DISABLE_CRASH_REPORTS
|
||||
return Restart();
|
||||
}
|
||||
|
||||
Status Restart() {
|
||||
#ifndef TDESKTOP_DISABLE_CRASH_REPORTS
|
||||
if (ReportFile) {
|
||||
return Started;
|
||||
}
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
if (_wfopen_s(&ReportFile, ReportPath.toStdWString().c_str(), L"wb") != 0) {
|
||||
ReportFile = nullptr;
|
||||
}
|
||||
#else // Q_OS_WIN
|
||||
ReportFile = fopen(QFile::encodeName(ReportPath).constData(), "wb");
|
||||
#endif // else for Q_OS_WIN
|
||||
if (ReportFile) {
|
||||
#ifdef Q_OS_WIN
|
||||
ReportFileNo = _fileno(ReportFile);
|
||||
#else // Q_OS_WIN
|
||||
ReportFileNo = fileno(ReportFile);
|
||||
#endif // else for Q_OS_WIN
|
||||
if (SetSignalHandlers) {
|
||||
#ifndef Q_OS_WIN
|
||||
struct sigaction sigact;
|
||||
|
||||
sigact.sa_sigaction = SignalHandler;
|
||||
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]);
|
||||
#else // !Q_OS_WIN
|
||||
signal(SIGABRT, SignalHandler);
|
||||
signal(SIGSEGV, SignalHandler);
|
||||
signal(SIGILL, SignalHandler);
|
||||
signal(SIGFPE, SignalHandler);
|
||||
#endif // else for !Q_OS_WIN
|
||||
}
|
||||
|
||||
InstallOperatorNewHandler();
|
||||
|
||||
return Started;
|
||||
}
|
||||
|
||||
LOG(("FATAL: Could not open '%1' for writing!").arg(ReportPath));
|
||||
|
||||
return CantOpen;
|
||||
#else // !TDESKTOP_DISABLE_CRASH_REPORTS
|
||||
return Started;
|
||||
#endif // else for !TDESKTOP_DISABLE_CRASH_REPORTS
|
||||
}
|
||||
|
||||
void Finish() {
|
||||
#ifndef TDESKTOP_DISABLE_CRASH_REPORTS
|
||||
FinishCatching();
|
||||
|
||||
if (ReportFile) {
|
||||
fclose(ReportFile);
|
||||
ReportFile = nullptr;
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
_wunlink(ReportPath.toStdWString().c_str());
|
||||
#else // Q_OS_WIN
|
||||
unlink(ReportPath.toUtf8().constData());
|
||||
#endif // else for Q_OS_WIN
|
||||
}
|
||||
#endif // !TDESKTOP_DISABLE_CRASH_REPORTS
|
||||
}
|
||||
|
||||
void SetAnnotation(const std::string &key, const QString &value) {
|
||||
static QMutex mutex;
|
||||
QMutexLocker lock(&mutex);
|
||||
|
||||
if (!value.trimmed().isEmpty()) {
|
||||
ProcessAnnotations[key] = value.toUtf8().constData();
|
||||
} else {
|
||||
ProcessAnnotations.erase(key);
|
||||
}
|
||||
}
|
||||
|
||||
void SetAnnotationRef(const std::string &key, const QString *valuePtr) {
|
||||
if (valuePtr) {
|
||||
ProcessAnnotationRefs[key] = valuePtr;
|
||||
} else {
|
||||
ProcessAnnotationRefs.erase(key);
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef TDESKTOP_DISABLE_CRASH_REPORTS
|
||||
|
||||
dump::~dump() {
|
||||
if (ReportFile) {
|
||||
fflush(ReportFile);
|
||||
}
|
||||
}
|
||||
|
||||
const dump &operator<<(const dump &stream, const char *str) {
|
||||
if (!ReportFile) return stream;
|
||||
|
||||
fwrite(str, 1, strlen(str), ReportFile);
|
||||
return stream;
|
||||
}
|
||||
|
||||
const dump &operator<<(const dump &stream, const wchar_t *str) {
|
||||
if (!ReportFile) return stream;
|
||||
|
||||
for (int i = 0, l = wcslen(str); i < l; ++i) {
|
||||
if (str[i] >= 0 && str[i] < 128) {
|
||||
SafeWriteChar(char(str[i]));
|
||||
} else {
|
||||
SafeWriteChar('?');
|
||||
}
|
||||
}
|
||||
return stream;
|
||||
}
|
||||
|
||||
const dump &operator<<(const dump &stream, int num) {
|
||||
return SafeWriteNumber(stream, num);
|
||||
}
|
||||
|
||||
const dump &operator<<(const dump &stream, unsigned int num) {
|
||||
return SafeWriteNumber(stream, num);
|
||||
}
|
||||
|
||||
const dump &operator<<(const dump &stream, unsigned long num) {
|
||||
return SafeWriteNumber(stream, num);
|
||||
}
|
||||
|
||||
const dump &operator<<(const dump &stream, unsigned long long num) {
|
||||
return SafeWriteNumber(stream, num);
|
||||
}
|
||||
|
||||
const dump &operator<<(const dump &stream, double num) {
|
||||
if (num < 0) {
|
||||
SafeWriteChar('-');
|
||||
num = -num;
|
||||
}
|
||||
SafeWriteNumber(stream, uint64(floor(num)));
|
||||
SafeWriteChar('.');
|
||||
num -= floor(num);
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
num *= 10;
|
||||
int digit = int(floor(num));
|
||||
SafeWriteChar('0' + digit);
|
||||
num -= digit;
|
||||
}
|
||||
return stream;
|
||||
}
|
||||
|
||||
#endif // TDESKTOP_DISABLE_CRASH_REPORTS
|
||||
|
||||
} // namespace CrashReports
|
||||
85
Telegram/SourceFiles/core/crash_reports.h
Normal file
85
Telegram/SourceFiles/core/crash_reports.h
Normal file
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop version of Telegram messaging app, see https://telegram.org
|
||||
|
||||
Telegram Desktop is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
It is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
In addition, as a special exception, the copyright holders give permission
|
||||
to link the code of portions of this program with the OpenSSL library.
|
||||
|
||||
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||
Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
namespace CrashReports {
|
||||
|
||||
#ifndef TDESKTOP_DISABLE_CRASH_REPORTS
|
||||
|
||||
struct dump {
|
||||
~dump();
|
||||
};
|
||||
const dump &operator<<(const dump &stream, const char *str);
|
||||
const dump &operator<<(const dump &stream, const wchar_t *str);
|
||||
const dump &operator<<(const dump &stream, int num);
|
||||
const dump &operator<<(const dump &stream, unsigned int num);
|
||||
const dump &operator<<(const dump &stream, unsigned long num);
|
||||
const dump &operator<<(const dump &stream, unsigned long long num);
|
||||
const dump &operator<<(const dump &stream, double num);
|
||||
|
||||
#endif // TDESKTOP_DISABLE_CRASH_REPORTS
|
||||
|
||||
enum Status {
|
||||
CantOpen,
|
||||
LastCrashed,
|
||||
Started
|
||||
};
|
||||
Status Start();
|
||||
Status Restart(); // can be only CantOpen or Started
|
||||
void Finish();
|
||||
|
||||
void SetAnnotation(const std::string &key, const QString &value);
|
||||
inline void ClearAnnotation(const std::string &key) {
|
||||
SetAnnotation(key, QString());
|
||||
}
|
||||
|
||||
// Remembers value pointer and tries to add the value to the crash report.
|
||||
// Attention! You should call clearCrashAnnotationRef(key) before destroying value.
|
||||
void SetAnnotationRef(const std::string &key, const QString *valuePtr);
|
||||
inline void ClearAnnotationRef(const std::string &key) {
|
||||
SetAnnotationRef(key, nullptr);
|
||||
}
|
||||
|
||||
void StartCatching();
|
||||
void FinishCatching();
|
||||
|
||||
} // namespace CrashReports
|
||||
|
||||
namespace base {
|
||||
namespace assertion {
|
||||
|
||||
inline void log(const char *message, const char *file, int line) {
|
||||
const auto info = QStringLiteral("%1 %2:%3"
|
||||
).arg(message
|
||||
).arg(file
|
||||
).arg(line
|
||||
);
|
||||
const auto entry = QStringLiteral("Assertion Failed! ") + info;
|
||||
|
||||
#ifdef LOG
|
||||
LOG((entry));
|
||||
#endif // LOG
|
||||
|
||||
CrashReports::SetAnnotation("Assertion", info);
|
||||
}
|
||||
|
||||
} // namespace assertion
|
||||
} // namespace base
|
||||
243
Telegram/SourceFiles/core/launcher.cpp
Normal file
243
Telegram/SourceFiles/core/launcher.cpp
Normal file
@@ -0,0 +1,243 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop version of Telegram messaging app, see https://telegram.org
|
||||
|
||||
Telegram Desktop is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
It is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
In addition, as a special exception, the copyright holders give permission
|
||||
to link the code of portions of this program with the OpenSSL library.
|
||||
|
||||
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||
Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||
*/
|
||||
#include "core/launcher.h"
|
||||
|
||||
#include "platform/platform_launcher.h"
|
||||
#include "platform/platform_specific.h"
|
||||
#include "core/crash_reports.h"
|
||||
#include "application.h"
|
||||
|
||||
namespace Core {
|
||||
|
||||
std::unique_ptr<Launcher> Launcher::Create(int argc, char *argv[]) {
|
||||
return std::make_unique<Platform::Launcher>(argc, argv);
|
||||
}
|
||||
|
||||
Launcher::Launcher(int argc, char *argv[])
|
||||
: _argc(argc)
|
||||
, _argv(argv) {
|
||||
}
|
||||
|
||||
void Launcher::init() {
|
||||
_arguments = readArguments(_argc, _argv);
|
||||
|
||||
prepareSettings();
|
||||
|
||||
QCoreApplication::setApplicationName(qsl("TelegramDesktop"));
|
||||
|
||||
#ifndef OS_MAC_OLD
|
||||
QCoreApplication::setAttribute(Qt::AA_DisableHighDpiScaling, true);
|
||||
#endif // OS_MAC_OLD
|
||||
|
||||
initHook();
|
||||
}
|
||||
|
||||
int Launcher::exec() {
|
||||
init();
|
||||
|
||||
if (cLaunchMode() == LaunchModeFixPrevious) {
|
||||
return psFixPrevious();
|
||||
} else if (cLaunchMode() == LaunchModeCleanup) {
|
||||
return psCleanup();
|
||||
}
|
||||
|
||||
// both are finished in Application::closeApplication
|
||||
Logs::start(this); // must be started before Platform is started
|
||||
Platform::start(); // must be started before QApplication is created
|
||||
|
||||
auto result = 0;
|
||||
{
|
||||
Application app(this, _argc, _argv);
|
||||
result = app.exec();
|
||||
}
|
||||
|
||||
DEBUG_LOG(("Telegram finished, result: %1").arg(result));
|
||||
|
||||
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
|
||||
if (cRestartingUpdate()) {
|
||||
DEBUG_LOG(("Application Info: executing updater to install update..."));
|
||||
if (!launchUpdater(UpdaterLaunch::PerformUpdate)) {
|
||||
psDeleteDir(cWorkingDir() + qsl("tupdates/temp"));
|
||||
}
|
||||
} else
|
||||
#endif // !TDESKTOP_DISABLE_AUTOUPDATE
|
||||
if (cRestarting()) {
|
||||
DEBUG_LOG(("Application Info: executing Telegram, because of restart..."));
|
||||
launchUpdater(UpdaterLaunch::JustRelaunch);
|
||||
}
|
||||
|
||||
CrashReports::Finish();
|
||||
Platform::finish();
|
||||
Logs::finish();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
QStringList Launcher::readArguments(int argc, char *argv[]) const {
|
||||
Expects(argc >= 0);
|
||||
|
||||
if (const auto native = readArgumentsHook(argc, argv)) {
|
||||
return *native;
|
||||
}
|
||||
|
||||
auto result = QStringList();
|
||||
result.reserve(argc);
|
||||
for (auto i = 0; i != argc; ++i) {
|
||||
result.push_back(fromUtf8Safe(argv[i]));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
QString Launcher::argumentsString() const {
|
||||
return _arguments.join(' ');
|
||||
}
|
||||
|
||||
void Launcher::prepareSettings() {
|
||||
#ifdef Q_OS_MAC
|
||||
#ifndef OS_MAC_OLD
|
||||
if (QSysInfo::macVersion() >= QSysInfo::MV_10_11) {
|
||||
gIsElCapitan = true;
|
||||
}
|
||||
#else // OS_MAC_OLD
|
||||
if (QSysInfo::macVersion() < QSysInfo::MV_10_7) {
|
||||
gIsSnowLeopard = true;
|
||||
}
|
||||
#endif // OS_MAC_OLD
|
||||
#endif // Q_OS_MAC
|
||||
|
||||
switch (cPlatform()) {
|
||||
case dbipWindows:
|
||||
gUpdateURL = QUrl(qsl("http://tdesktop.com/win/tupdates/current"));
|
||||
#ifndef OS_WIN_STORE
|
||||
gPlatformString = qsl("Windows");
|
||||
#else // OS_WIN_STORE
|
||||
gPlatformString = qsl("WinStore");
|
||||
#endif // OS_WIN_STORE
|
||||
break;
|
||||
case dbipMac:
|
||||
gUpdateURL = QUrl(qsl("http://tdesktop.com/mac/tupdates/current"));
|
||||
#ifndef OS_MAC_STORE
|
||||
gPlatformString = qsl("MacOS");
|
||||
#else // OS_MAC_STORE
|
||||
gPlatformString = qsl("MacAppStore");
|
||||
#endif // OS_MAC_STORE
|
||||
break;
|
||||
case dbipMacOld:
|
||||
gUpdateURL = QUrl(qsl("http://tdesktop.com/mac32/tupdates/current"));
|
||||
gPlatformString = qsl("MacOSold");
|
||||
break;
|
||||
case dbipLinux64:
|
||||
gUpdateURL = QUrl(qsl("http://tdesktop.com/linux/tupdates/current"));
|
||||
gPlatformString = qsl("Linux64bit");
|
||||
break;
|
||||
case dbipLinux32:
|
||||
gUpdateURL = QUrl(qsl("http://tdesktop.com/linux32/tupdates/current"));
|
||||
gPlatformString = qsl("Linux32bit");
|
||||
break;
|
||||
}
|
||||
|
||||
auto path = Platform::CurrentExecutablePath(_argc, _argv);
|
||||
LOG(("Executable path before check: %1").arg(path));
|
||||
if (!path.isEmpty()) {
|
||||
auto info = QFileInfo(path);
|
||||
if (info.isSymLink()) {
|
||||
info = info.symLinkTarget();
|
||||
}
|
||||
if (info.exists()) {
|
||||
gExeDir = info.absoluteDir().absolutePath() + '/';
|
||||
gExeName = info.fileName();
|
||||
}
|
||||
}
|
||||
if (cExeName().isEmpty()) {
|
||||
LOG(("WARNING: Could not compute executable path, some features will be disabled."));
|
||||
}
|
||||
|
||||
processArguments();
|
||||
}
|
||||
|
||||
void Launcher::processArguments() {
|
||||
enum class KeyFormat {
|
||||
NoValues,
|
||||
OneValue,
|
||||
AllLeftValues,
|
||||
};
|
||||
auto parseMap = std::map<QByteArray, KeyFormat> {
|
||||
{ "-testmode" , KeyFormat::NoValues },
|
||||
{ "-debug" , KeyFormat::NoValues },
|
||||
{ "-many" , KeyFormat::NoValues },
|
||||
{ "-key" , KeyFormat::OneValue },
|
||||
{ "-autostart" , KeyFormat::NoValues },
|
||||
{ "-fixprevious", KeyFormat::NoValues },
|
||||
{ "-cleanup" , KeyFormat::NoValues },
|
||||
{ "-noupdate" , KeyFormat::NoValues },
|
||||
{ "-tosettings" , KeyFormat::NoValues },
|
||||
{ "-startintray", KeyFormat::NoValues },
|
||||
{ "-sendpath" , KeyFormat::AllLeftValues },
|
||||
{ "-workdir" , KeyFormat::OneValue },
|
||||
{ "--" , KeyFormat::OneValue },
|
||||
};
|
||||
auto parseResult = QMap<QByteArray, QStringList>();
|
||||
auto parsingKey = QByteArray();
|
||||
auto parsingFormat = KeyFormat::NoValues;
|
||||
for (const auto &argument : _arguments) {
|
||||
switch (parsingFormat) {
|
||||
case KeyFormat::OneValue: {
|
||||
parseResult[parsingKey] = QStringList(argument.mid(0, 8192));
|
||||
parsingFormat = KeyFormat::NoValues;
|
||||
} break;
|
||||
case KeyFormat::AllLeftValues: {
|
||||
parseResult[parsingKey].push_back(argument.mid(0, 8192));
|
||||
} break;
|
||||
case KeyFormat::NoValues: {
|
||||
parsingKey = argument.toLatin1();
|
||||
auto it = parseMap.find(parsingKey);
|
||||
if (it != parseMap.end()) {
|
||||
parsingFormat = it->second;
|
||||
parseResult[parsingKey] = QStringList();
|
||||
}
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
gTestMode = parseResult.contains("-testmode");
|
||||
gDebug = parseResult.contains("-debug");
|
||||
gManyInstance = parseResult.contains("-many");
|
||||
gKeyFile = parseResult.value("-key", QStringList()).join(QString());
|
||||
gLaunchMode = parseResult.contains("-autostart") ? LaunchModeAutoStart
|
||||
: parseResult.contains("-fixprevious") ? LaunchModeFixPrevious
|
||||
: parseResult.contains("-cleanup") ? LaunchModeCleanup
|
||||
: LaunchModeNormal;
|
||||
gNoStartUpdate = parseResult.contains("-noupdate");
|
||||
gStartToSettings = parseResult.contains("-tosettings");
|
||||
gStartInTray = parseResult.contains("-startintray");
|
||||
gSendPaths = parseResult.value("-sendpath", QStringList());
|
||||
gWorkingDir = parseResult.value("-workdir", QStringList()).join(QString());
|
||||
if (!gWorkingDir.isEmpty()) {
|
||||
if (QDir().exists(gWorkingDir)) {
|
||||
_customWorkingDir = true;
|
||||
} else {
|
||||
gWorkingDir = QString();
|
||||
}
|
||||
}
|
||||
gStartUrl = parseResult.value("--", QStringList()).join(QString());
|
||||
}
|
||||
|
||||
} // namespace Core
|
||||
70
Telegram/SourceFiles/core/launcher.h
Normal file
70
Telegram/SourceFiles/core/launcher.h
Normal file
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop version of Telegram messaging app, see https://telegram.org
|
||||
|
||||
Telegram Desktop is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
It is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
In addition, as a special exception, the copyright holders give permission
|
||||
to link the code of portions of this program with the OpenSSL library.
|
||||
|
||||
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||
Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
namespace Core {
|
||||
|
||||
class Launcher {
|
||||
public:
|
||||
Launcher(int argc, char *argv[]);
|
||||
|
||||
static std::unique_ptr<Launcher> Create(int argc, char *argv[]);
|
||||
|
||||
int exec();
|
||||
|
||||
QString argumentsString() const;
|
||||
bool customWorkingDir() const {
|
||||
return _customWorkingDir;
|
||||
}
|
||||
|
||||
protected:
|
||||
enum class UpdaterLaunch {
|
||||
PerformUpdate,
|
||||
JustRelaunch,
|
||||
};
|
||||
|
||||
private:
|
||||
void prepareSettings();
|
||||
void processArguments();
|
||||
|
||||
QStringList readArguments(int argc, char *argv[]) const;
|
||||
virtual base::optional<QStringList> readArgumentsHook(
|
||||
int argc,
|
||||
char *argv[]) const {
|
||||
return base::none;
|
||||
}
|
||||
|
||||
void init();
|
||||
virtual void initHook() {
|
||||
}
|
||||
|
||||
virtual bool launchUpdater(UpdaterLaunch action) = 0;
|
||||
|
||||
|
||||
int _argc;
|
||||
char **_argv;
|
||||
QStringList _arguments;
|
||||
|
||||
bool _customWorkingDir = false;
|
||||
|
||||
};
|
||||
|
||||
} // namespace Core
|
||||
@@ -24,7 +24,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||
|
||||
#define BETA_VERSION_MACRO (0ULL)
|
||||
|
||||
constexpr int AppVersion = 1002000;
|
||||
constexpr str_const AppVersionStr = "1.2";
|
||||
constexpr int AppVersion = 1002001;
|
||||
constexpr str_const AppVersionStr = "1.2.1";
|
||||
constexpr bool AppAlphaVersion = false;
|
||||
constexpr uint64 AppBetaVersion = BETA_VERSION_MACRO;
|
||||
|
||||
@@ -277,12 +277,7 @@ void PeerData::updateUserpic(
|
||||
const auto size = kUserpicSize;
|
||||
const auto loc = StorageImageLocation::FromMTP(size, size, location);
|
||||
const auto photo = loc.isNull() ? ImagePtr() : ImagePtr(loc);
|
||||
if (_userpicPhotoId != photoId
|
||||
|| _userpic.v() != photo.v()
|
||||
|| _userpicLocation != loc) {
|
||||
setUserpic(photoId, loc, photo);
|
||||
Notify::peerUpdatedDelayed(this, UpdateFlag::PhotoChanged);
|
||||
}
|
||||
setUserpicChecked(photoId, loc, photo);
|
||||
}
|
||||
|
||||
void PeerData::clearUserpic() {
|
||||
@@ -300,6 +295,19 @@ void PeerData::clearUserpic() {
|
||||
}
|
||||
return ImagePtr();
|
||||
}();
|
||||
setUserpicChecked(photoId, loc, photo);
|
||||
}
|
||||
|
||||
void PeerData::setUserpicChecked(
|
||||
PhotoId photoId,
|
||||
const StorageImageLocation &location,
|
||||
ImagePtr userpic) {
|
||||
if (_userpicPhotoId != photoId
|
||||
|| _userpic.v() != userpic.v()
|
||||
|| _userpicLocation != location) {
|
||||
setUserpic(photoId, location, userpic);
|
||||
Notify::peerUpdatedDelayed(this, UpdateFlag::PhotoChanged);
|
||||
}
|
||||
}
|
||||
|
||||
void PeerData::fillNames() {
|
||||
|
||||
@@ -238,6 +238,11 @@ private:
|
||||
std::unique_ptr<Ui::EmptyUserpic> createEmptyUserpic() const;
|
||||
void refreshEmptyUserpic() const;
|
||||
|
||||
void setUserpicChecked(
|
||||
PhotoId photoId,
|
||||
const StorageImageLocation &location,
|
||||
ImagePtr userpic);
|
||||
|
||||
static constexpr auto kUnknownPhotoId = PhotoId(0xFFFFFFFFFFFFFFFFULL);
|
||||
|
||||
ImagePtr _userpic;
|
||||
|
||||
@@ -36,6 +36,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||
#include "apiwrap.h"
|
||||
#include "window/themes/window_theme.h"
|
||||
#include "observer_peer.h"
|
||||
#include "chat_helpers/stickers.h"
|
||||
#include "auth_session.h"
|
||||
#include "window/notifications_manager.h"
|
||||
#include "window/window_controller.h"
|
||||
@@ -2123,7 +2124,7 @@ void DialogsInner::saveRecentHashtags(const QString &text) {
|
||||
recent = cRecentSearchHashtags();
|
||||
}
|
||||
found = true;
|
||||
incrementRecentHashtag(recent, text.mid(i + 1, next - i - 1));
|
||||
Stickers::IncrementRecentHashtag(recent, text.mid(i + 1, next - i - 1));
|
||||
}
|
||||
if (found) {
|
||||
cSetRecentSearchHashtags(recent);
|
||||
|
||||
@@ -38,6 +38,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||
#include "storage/storage_facade.h"
|
||||
#include "storage/storage_shared_media.h"
|
||||
#include "data/data_channel_admins.h"
|
||||
#include "core/crash_reports.h"
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -1499,7 +1500,7 @@ void History::addToSharedMedia(std::vector<MsgId> (&medias)[kSharedMediaTypeCoun
|
||||
}
|
||||
value.push_back(indices.join(","));
|
||||
}
|
||||
SignalHandlers::setCrashAnnotation("full", value.join(";"));
|
||||
CrashReports::SetAnnotation("full", value.join(";"));
|
||||
Assert(!"History desync caught!");
|
||||
//// Logging
|
||||
|
||||
@@ -1631,11 +1632,11 @@ void History::addOlderSlice(const QVector<MTPMessage> &slice) {
|
||||
|
||||
logged.push_back(QString::number(minAdded));
|
||||
logged.push_back(QString::number(maxAdded));
|
||||
SignalHandlers::setCrashAnnotation("old_minmaxwas_minmaxadd", logged.join(";"));
|
||||
CrashReports::SetAnnotation("old_minmaxwas_minmaxadd", logged.join(";"));
|
||||
|
||||
addBlockToSharedMedia(block);
|
||||
|
||||
SignalHandlers::setCrashAnnotation("old_minmaxwas_minmaxadd", "");
|
||||
CrashReports::ClearAnnotation("old_minmaxwas_minmaxadd");
|
||||
|
||||
if (isChannel()) {
|
||||
asChannelHistory()->checkJoinedMessage();
|
||||
@@ -1693,7 +1694,7 @@ void History::addNewerSlice(const QVector<MTPMessage> &slice) {
|
||||
}
|
||||
logged.push_back(QString::number(minAdded));
|
||||
logged.push_back(QString::number(maxAdded));
|
||||
SignalHandlers::setCrashAnnotation("new_minmaxwas_minmaxadd", logged.join(";"));
|
||||
CrashReports::SetAnnotation("new_minmaxwas_minmaxadd", logged.join(";"));
|
||||
|
||||
if (!atLeastOneAdded) {
|
||||
newLoaded = true;
|
||||
@@ -1701,7 +1702,7 @@ void History::addNewerSlice(const QVector<MTPMessage> &slice) {
|
||||
}
|
||||
addToSharedMedia(medias, wasLoadedAtBottom != loadedAtBottom());
|
||||
|
||||
SignalHandlers::setCrashAnnotation("new_minmaxwas_minmaxadd", "");
|
||||
CrashReports::ClearAnnotation("new_minmaxwas_minmaxadd");
|
||||
}
|
||||
|
||||
if (!wasLoadedAtBottom) {
|
||||
|
||||
@@ -79,6 +79,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||
#include "window/window_peer_menu.h"
|
||||
#include "inline_bots/inline_results_widget.h"
|
||||
#include "chat_helpers/emoji_suggestions_widget.h"
|
||||
#include "core/crash_reports.h"
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -2292,7 +2293,7 @@ void HistoryWidget::messagesReceived(PeerData *peer, const MTPmessages_Messages
|
||||
if (_preloadRequest == requestId) {
|
||||
auto to = toMigrated ? _migrated : _history;
|
||||
if (cBetaVersion()) {
|
||||
SignalHandlers::setCrashAnnotation("old_debugstr", QString(
|
||||
CrashReports::SetAnnotation("old_debugstr", QString(
|
||||
"%1_%2_%3_%4:%5_%6 (%7)"
|
||||
).arg(PeerString(_debug_preloadDownPeer)
|
||||
).arg(_debug_preloadOffsetId
|
||||
@@ -2307,7 +2308,7 @@ void HistoryWidget::messagesReceived(PeerData *peer, const MTPmessages_Messages
|
||||
addMessagesToFront(peer, *histList);
|
||||
|
||||
if (cBetaVersion()) {
|
||||
SignalHandlers::setCrashAnnotation("old_debugstr", QString());
|
||||
CrashReports::ClearAnnotation("old_debugstr");
|
||||
}
|
||||
|
||||
_preloadRequest = 0;
|
||||
@@ -2319,7 +2320,7 @@ void HistoryWidget::messagesReceived(PeerData *peer, const MTPmessages_Messages
|
||||
} else if (_preloadDownRequest == requestId) {
|
||||
auto to = toMigrated ? _migrated : _history;
|
||||
if (cBetaVersion()) {
|
||||
SignalHandlers::setCrashAnnotation("new_debugstr", QString(
|
||||
CrashReports::SetAnnotation("new_debugstr", QString(
|
||||
"%1_%2_%3_%4:%5_%6 (%7)"
|
||||
).arg(PeerString(_debug_preloadDownPeer)
|
||||
).arg(_debug_preloadDownOffsetId
|
||||
@@ -2334,7 +2335,7 @@ void HistoryWidget::messagesReceived(PeerData *peer, const MTPmessages_Messages
|
||||
addMessagesToBack(peer, *histList);
|
||||
|
||||
if (cBetaVersion()) {
|
||||
SignalHandlers::setCrashAnnotation("new_debugstr", QString());
|
||||
CrashReports::ClearAnnotation("new_debugstr");
|
||||
}
|
||||
|
||||
_preloadDownRequest = 0;
|
||||
|
||||
@@ -260,10 +260,18 @@ Cover::Cover(
|
||||
|
||||
void Cover::setupChildGeometry() {
|
||||
using namespace rpl::mappers;
|
||||
//
|
||||
// Visual Studio 2017 15.5.1 internal compiler error here.
|
||||
// See https://developercommunity.visualstudio.com/content/problem/165155/ice-regression-in-1551-after-successfull-build-in.html
|
||||
//
|
||||
//rpl::combine(
|
||||
// toggleShownValue(),
|
||||
// widthValue(),
|
||||
// _2)
|
||||
rpl::combine(
|
||||
toggleShownValue(),
|
||||
widthValue(),
|
||||
_2)
|
||||
widthValue())
|
||||
| rpl::map([](bool shown, int width) { return width; })
|
||||
| rpl::start_with_next([this](int newWidth) {
|
||||
_userpic->moveToLeft(
|
||||
st::infoProfilePhotoLeft,
|
||||
@@ -449,10 +457,18 @@ void SharedMediaCover::createLabel() {
|
||||
Lang::Viewer(lng_profile_shared_media) | ToUpperValue(),
|
||||
st::infoBlockHeaderLabel);
|
||||
label->setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||
//
|
||||
// Visual Studio 2017 15.5.1 internal compiler error here.
|
||||
// See https://developercommunity.visualstudio.com/content/problem/165155/ice-regression-in-1551-after-successfull-build-in.html
|
||||
//
|
||||
//rpl::combine(
|
||||
// toggleShownValue(),
|
||||
// widthValue(),
|
||||
// _2)
|
||||
rpl::combine(
|
||||
toggleShownValue(),
|
||||
widthValue(),
|
||||
_2)
|
||||
widthValue())
|
||||
| rpl::map([](bool shown, int width) { return width; })
|
||||
| rpl::start_with_next([this, weak = label.data()](int newWidth) {
|
||||
auto availableWidth = newWidth
|
||||
- st::infoBlockHeaderPosition.x()
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -20,60 +20,61 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
class MTPlong;
|
||||
namespace Core {
|
||||
class Launcher;
|
||||
} // namespace Core
|
||||
|
||||
namespace Logs {
|
||||
|
||||
void start();
|
||||
bool started();
|
||||
void finish();
|
||||
void start(not_null<Core::Launcher*> launcher);
|
||||
bool started();
|
||||
void finish();
|
||||
|
||||
bool instanceChecked();
|
||||
void multipleInstances();
|
||||
bool instanceChecked();
|
||||
void multipleInstances();
|
||||
|
||||
void closeMain();
|
||||
void closeMain();
|
||||
|
||||
void writeMain(const QString &v);
|
||||
void writeMain(const QString &v);
|
||||
|
||||
void writeDebug(const char *file, int32 line, const QString &v);
|
||||
void writeTcp(const QString &v);
|
||||
void writeMtp(int32 dc, const QString &v);
|
||||
void writeDebug(const char *file, int32 line, const QString &v);
|
||||
void writeTcp(const QString &v);
|
||||
void writeMtp(int32 dc, const QString &v);
|
||||
|
||||
QString full();
|
||||
|
||||
inline const char *b(bool v) {
|
||||
return v ? "[TRUE]" : "[FALSE]";
|
||||
}
|
||||
|
||||
struct MemoryBuffer {
|
||||
MemoryBuffer(const void *ptr, uint32 size) : p(ptr), s(size) {
|
||||
}
|
||||
QString str() const {
|
||||
QString result;
|
||||
const uchar *buf((const uchar*)p);
|
||||
const char *hex = "0123456789ABCDEF";
|
||||
result.reserve(s * 3);
|
||||
for (uint32 i = 0; i < s; ++i) {
|
||||
result += hex[(buf[i] >> 4)];
|
||||
result += hex[buf[i] & 0x0F];
|
||||
result += ' ';
|
||||
}
|
||||
result.chop(1);
|
||||
return result;
|
||||
}
|
||||
|
||||
const void *p;
|
||||
uint32 s;
|
||||
};
|
||||
|
||||
inline MemoryBuffer mb(const void *ptr, uint32 size) {
|
||||
return MemoryBuffer(ptr, size);
|
||||
}
|
||||
|
||||
QString vector(const QVector<MTPlong> &ids);
|
||||
QString vector(const QVector<uint64> &ids);
|
||||
QString full();
|
||||
|
||||
inline const char *b(bool v) {
|
||||
return v ? "[TRUE]" : "[FALSE]";
|
||||
}
|
||||
|
||||
struct MemoryBuffer {
|
||||
MemoryBuffer(const void *ptr, uint32 size) : p(ptr), s(size) {
|
||||
}
|
||||
QString str() const {
|
||||
QString result;
|
||||
const uchar *buf((const uchar*)p);
|
||||
const char *hex = "0123456789ABCDEF";
|
||||
result.reserve(s * 3);
|
||||
for (uint32 i = 0; i < s; ++i) {
|
||||
result += hex[(buf[i] >> 4)];
|
||||
result += hex[buf[i] & 0x0F];
|
||||
result += ' ';
|
||||
}
|
||||
result.chop(1);
|
||||
return result;
|
||||
}
|
||||
|
||||
const void *p;
|
||||
uint32 s;
|
||||
|
||||
};
|
||||
|
||||
inline MemoryBuffer mb(const void *ptr, uint32 size) {
|
||||
return MemoryBuffer(ptr, size);
|
||||
}
|
||||
|
||||
} // namespace Logs
|
||||
|
||||
#define LOG(msg) (Logs::writeMain(QString msg))
|
||||
//usage LOG(("log: %1 %2").arg(1).arg(2))
|
||||
|
||||
@@ -85,47 +86,3 @@ namespace Logs {
|
||||
|
||||
#define MTP_LOG(dc, msg) { if (cDebug() || !Logs::started()) Logs::writeMtp(dc, QString msg); }
|
||||
//usage MTP_LOG(dc, ("log: %1 %2").arg(1).arg(2))
|
||||
|
||||
namespace SignalHandlers {
|
||||
|
||||
struct dump {
|
||||
~dump();
|
||||
};
|
||||
const dump &operator<<(const dump &stream, const char *str);
|
||||
const dump &operator<<(const dump &stream, const wchar_t *str);
|
||||
const dump &operator<<(const dump &stream, int num);
|
||||
const dump &operator<<(const dump &stream, unsigned int num);
|
||||
const dump &operator<<(const dump &stream, unsigned long num);
|
||||
const dump &operator<<(const dump &stream, unsigned long long num);
|
||||
const dump &operator<<(const dump &stream, double num);
|
||||
enum Status {
|
||||
CantOpen,
|
||||
LastCrashed,
|
||||
Started
|
||||
};
|
||||
Status start();
|
||||
Status restart(); // can be only CantOpen or Started
|
||||
void finish();
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace base {
|
||||
namespace assertion {
|
||||
|
||||
inline void log(const char *message, const char *file, int line) {
|
||||
auto info = QStringLiteral("%1 %2:%3").arg(message).arg(file).arg(line);
|
||||
LOG(("Assertion Failed! ") + info);
|
||||
SignalHandlers::setCrashAnnotation("Assertion", info);
|
||||
}
|
||||
|
||||
} // namespace assertion
|
||||
} // namespace base
|
||||
|
||||
@@ -18,49 +18,9 @@ to link the code of portions of this program with the OpenSSL library.
|
||||
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||
Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||
*/
|
||||
#include "application.h"
|
||||
#include "platform/platform_specific.h"
|
||||
#include "storage/localstorage.h"
|
||||
#include "core/launcher.h"
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
#ifndef Q_OS_MAC // Retina display support is working fine, others are not.
|
||||
QCoreApplication::setAttribute(Qt::AA_DisableHighDpiScaling, true);
|
||||
#endif // Q_OS_MAC
|
||||
QCoreApplication::setApplicationName(qsl("TelegramDesktop"));
|
||||
|
||||
InitFromCommandLine(argc, argv);
|
||||
if (cLaunchMode() == LaunchModeFixPrevious) {
|
||||
return psFixPrevious();
|
||||
} else if (cLaunchMode() == LaunchModeCleanup) {
|
||||
return psCleanup();
|
||||
}
|
||||
|
||||
// both are finished in Application::closeApplication
|
||||
Logs::start(); // must be started before Platform is started
|
||||
Platform::start(); // must be started before QApplication is created
|
||||
|
||||
int result = 0;
|
||||
{
|
||||
Application app(argc, argv);
|
||||
result = app.exec();
|
||||
}
|
||||
|
||||
DEBUG_LOG(("Telegram finished, result: %1").arg(result));
|
||||
|
||||
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
|
||||
if (cRestartingUpdate()) {
|
||||
DEBUG_LOG(("Application Info: executing updater to install update..."));
|
||||
psExecUpdater();
|
||||
} else
|
||||
#endif // !TDESKTOP_DISABLE_AUTOUPDATE
|
||||
if (cRestarting()) {
|
||||
DEBUG_LOG(("Application Info: executing Telegram, because of restart..."));
|
||||
psExecTelegram();
|
||||
}
|
||||
|
||||
SignalHandlers::finish();
|
||||
Platform::finish();
|
||||
Logs::finish();
|
||||
|
||||
return result;
|
||||
const auto launcher = Core::Launcher::Create(argc, argv);
|
||||
return launcher ? launcher->exec() : 1;
|
||||
}
|
||||
|
||||
@@ -1574,7 +1574,7 @@ void MainWidget::saveRecentHashtags(const QString &text) {
|
||||
recent = cRecentWriteHashtags();
|
||||
}
|
||||
found = true;
|
||||
incrementRecentHashtag(recent, text.mid(i + 1, next - i - 1));
|
||||
Stickers::IncrementRecentHashtag(recent, text.mid(i + 1, next - i - 1));
|
||||
}
|
||||
if (found) {
|
||||
cSetRecentWriteHashtags(recent);
|
||||
@@ -4389,7 +4389,7 @@ void MainWidget::incrementSticker(DocumentData *sticker) {
|
||||
|
||||
// Remove that sticker from old recent, now it is in cloud recent stickers.
|
||||
bool writeOldRecent = false;
|
||||
auto &recent = cGetRecentStickers();
|
||||
auto &recent = Stickers::GetRecentPack();
|
||||
for (auto i = recent.begin(), e = recent.end(); i != e; ++i) {
|
||||
if (i->first == sticker) {
|
||||
writeOldRecent = true;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -224,219 +224,3 @@ private:
|
||||
Local::ClearManager *_clearManager = nullptr;
|
||||
|
||||
};
|
||||
|
||||
class PreLaunchWindow : public TWidget {
|
||||
public:
|
||||
|
||||
PreLaunchWindow(QString title = QString());
|
||||
void activate();
|
||||
int basicSize() const {
|
||||
return _size;
|
||||
}
|
||||
~PreLaunchWindow();
|
||||
|
||||
static PreLaunchWindow *instance();
|
||||
|
||||
protected:
|
||||
|
||||
int _size;
|
||||
|
||||
};
|
||||
|
||||
class PreLaunchLabel : public QLabel {
|
||||
public:
|
||||
PreLaunchLabel(QWidget *parent);
|
||||
void setText(const QString &text);
|
||||
};
|
||||
|
||||
class PreLaunchInput : public QLineEdit {
|
||||
public:
|
||||
PreLaunchInput(QWidget *parent, bool password = false);
|
||||
};
|
||||
|
||||
class PreLaunchLog : public QTextEdit {
|
||||
public:
|
||||
PreLaunchLog(QWidget *parent);
|
||||
};
|
||||
|
||||
class PreLaunchButton : public QPushButton {
|
||||
public:
|
||||
PreLaunchButton(QWidget *parent, bool confirm = true);
|
||||
void setText(const QString &text);
|
||||
};
|
||||
|
||||
class PreLaunchCheckbox : public QCheckBox {
|
||||
public:
|
||||
PreLaunchCheckbox(QWidget *parent);
|
||||
void setText(const QString &text);
|
||||
};
|
||||
|
||||
class NotStartedWindow : public PreLaunchWindow {
|
||||
public:
|
||||
|
||||
NotStartedWindow();
|
||||
|
||||
protected:
|
||||
|
||||
void closeEvent(QCloseEvent *e);
|
||||
void resizeEvent(QResizeEvent *e);
|
||||
|
||||
private:
|
||||
|
||||
void updateControls();
|
||||
|
||||
PreLaunchLabel _label;
|
||||
PreLaunchLog _log;
|
||||
PreLaunchButton _close;
|
||||
|
||||
};
|
||||
|
||||
class LastCrashedWindow : public PreLaunchWindow {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
LastCrashedWindow();
|
||||
|
||||
public slots:
|
||||
|
||||
void onViewReport();
|
||||
void onSaveReport();
|
||||
void onSendReport();
|
||||
void onGetApp();
|
||||
|
||||
void onNetworkSettings();
|
||||
void onNetworkSettingsSaved(QString host, quint32 port, QString username, QString password);
|
||||
void onContinue();
|
||||
|
||||
void onCheckingFinished();
|
||||
void onSendingError(QNetworkReply::NetworkError e);
|
||||
void onSendingFinished();
|
||||
void onSendingProgress(qint64 uploaded, qint64 total);
|
||||
|
||||
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
|
||||
void onUpdateRetry();
|
||||
void onUpdateSkip();
|
||||
|
||||
void onUpdateChecking();
|
||||
void onUpdateLatest();
|
||||
void onUpdateDownloading(qint64 ready, qint64 total);
|
||||
void onUpdateReady();
|
||||
void onUpdateFailed();
|
||||
#endif // !TDESKTOP_DISABLE_AUTOUPDATE
|
||||
|
||||
protected:
|
||||
|
||||
void closeEvent(QCloseEvent *e);
|
||||
void resizeEvent(QResizeEvent *e);
|
||||
|
||||
private:
|
||||
|
||||
QString minidumpFileName();
|
||||
void updateControls();
|
||||
|
||||
QString _host, _username, _password;
|
||||
quint32 _port;
|
||||
|
||||
PreLaunchLabel _label, _pleaseSendReport, _yourReportName, _minidump;
|
||||
PreLaunchLog _report;
|
||||
PreLaunchButton _send, _sendSkip, _networkSettings, _continue, _showReport, _saveReport, _getApp;
|
||||
PreLaunchCheckbox _includeUsername;
|
||||
|
||||
QString _minidumpName, _minidumpFull, _reportText;
|
||||
QString _reportUsername, _reportTextNoUsername;
|
||||
QByteArray getCrashReportRaw() const;
|
||||
|
||||
bool _reportShown, _reportSaved;
|
||||
|
||||
void excludeReportUsername();
|
||||
|
||||
enum SendingState {
|
||||
SendingNoReport,
|
||||
SendingUpdateCheck,
|
||||
SendingNone,
|
||||
SendingTooOld,
|
||||
SendingTooMany,
|
||||
SendingUnofficial,
|
||||
SendingProgress,
|
||||
SendingUploading,
|
||||
SendingFail,
|
||||
SendingDone,
|
||||
};
|
||||
SendingState _sendingState;
|
||||
|
||||
PreLaunchLabel _updating;
|
||||
qint64 _sendingProgress, _sendingTotal;
|
||||
|
||||
QNetworkAccessManager _sendManager;
|
||||
QNetworkReply *_checkReply, *_sendReply;
|
||||
|
||||
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
|
||||
PreLaunchButton _updatingCheck, _updatingSkip;
|
||||
enum UpdatingState {
|
||||
UpdatingNone,
|
||||
UpdatingCheck,
|
||||
UpdatingLatest,
|
||||
UpdatingDownload,
|
||||
UpdatingFail,
|
||||
UpdatingReady
|
||||
};
|
||||
UpdatingState _updatingState;
|
||||
QString _newVersionDownload;
|
||||
|
||||
void setUpdatingState(UpdatingState state, bool force = false);
|
||||
void setDownloadProgress(qint64 ready, qint64 total);
|
||||
#endif // !TDESKTOP_DISABLE_AUTOUPDATE
|
||||
|
||||
QString getReportField(const QLatin1String &name, const QLatin1String &prefix);
|
||||
void addReportFieldPart(const QLatin1String &name, const QLatin1String &prefix, QHttpMultiPart *multipart);
|
||||
|
||||
};
|
||||
|
||||
class NetworkSettingsWindow : public PreLaunchWindow {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
NetworkSettingsWindow(QWidget *parent, QString host, quint32 port, QString username, QString password);
|
||||
|
||||
signals:
|
||||
|
||||
void saved(QString host, quint32 port, QString username, QString password);
|
||||
|
||||
public slots:
|
||||
|
||||
void onSave();
|
||||
|
||||
protected:
|
||||
|
||||
void closeEvent(QCloseEvent *e);
|
||||
void resizeEvent(QResizeEvent *e);
|
||||
|
||||
private:
|
||||
|
||||
void updateControls();
|
||||
|
||||
PreLaunchLabel _hostLabel, _portLabel, _usernameLabel, _passwordLabel;
|
||||
PreLaunchInput _hostInput, _portInput, _usernameInput, _passwordInput;
|
||||
PreLaunchButton _save, _cancel;
|
||||
|
||||
QWidget *_parent;
|
||||
|
||||
};
|
||||
|
||||
class ShowCrashReportWindow : public PreLaunchWindow {
|
||||
public:
|
||||
|
||||
ShowCrashReportWindow(const QString &text);
|
||||
|
||||
protected:
|
||||
|
||||
void resizeEvent(QResizeEvent *e);
|
||||
void closeEvent(QCloseEvent *e);
|
||||
|
||||
private:
|
||||
|
||||
PreLaunchLog _log;
|
||||
|
||||
};
|
||||
|
||||
@@ -20,6 +20,8 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||
*/
|
||||
#include "media/media_audio_ffmpeg_loader.h"
|
||||
|
||||
#include "core/crash_reports.h"
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr AVSampleFormat AudioToFormat = AV_SAMPLE_FMT_S16;
|
||||
@@ -423,7 +425,7 @@ AudioPlayerLoader::ReadResult FFMpegLoader::readFromReadyFrame(QByteArray &resul
|
||||
).arg(ptrdiff_t(frame->extended_data[0])
|
||||
).arg(ptrdiff_t(frame->data[1])
|
||||
);
|
||||
SignalHandlers::setCrashAnnotation(key, value);
|
||||
CrashReports::SetAnnotation(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -435,7 +437,7 @@ AudioPlayerLoader::ReadResult FFMpegLoader::readFromReadyFrame(QByteArray &resul
|
||||
|
||||
if (frame->extended_data[1] == nullptr) {
|
||||
const auto key = "ffmpeg_" + std::to_string(ptrdiff_t(this));
|
||||
SignalHandlers::setCrashAnnotation(key, QString());
|
||||
CrashReports::ClearAnnotation(key);
|
||||
}
|
||||
|
||||
int32 resultLen = av_samples_get_buffer_size(0, AudioToChannels, res, AudioToFormat, 1);
|
||||
|
||||
@@ -20,10 +20,25 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||
*/
|
||||
#include "media/media_child_ffmpeg_loader.h"
|
||||
|
||||
#include "core/crash_reports.h"
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr AVSampleFormat AudioToFormat = AV_SAMPLE_FMT_S16;
|
||||
constexpr int64_t AudioToChannelLayout = AV_CH_LAYOUT_STEREO;
|
||||
constexpr int32 AudioToChannels = 2;
|
||||
|
||||
bool IsPlanarFormat(int format) {
|
||||
return (format == AV_SAMPLE_FMT_U8P)
|
||||
|| (format == AV_SAMPLE_FMT_S16P)
|
||||
|| (format == AV_SAMPLE_FMT_S32P)
|
||||
|| (format == AV_SAMPLE_FMT_FLTP)
|
||||
|| (format == AV_SAMPLE_FMT_DBLP)
|
||||
|| (format == AV_SAMPLE_FMT_S64P);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
VideoSoundData::~VideoSoundData() {
|
||||
if (context) {
|
||||
avcodec_close(context);
|
||||
@@ -179,11 +194,48 @@ AudioPlayerLoader::ReadResult ChildFFMpegLoader::readFromReadyFrame(QByteArray &
|
||||
return ReadResult::Error;
|
||||
}
|
||||
}
|
||||
|
||||
// See the same check in media_audio_ffmpeg_loader.cpp.
|
||||
if (_frame->extended_data[1] == nullptr) {
|
||||
const auto params = _parentData->context;
|
||||
if (IsPlanarFormat(params->sample_fmt) && params->channels > 1) {
|
||||
LOG(("Audio Error: Inconsistent frame layout/channels in file, codec: (%1;%2;%3), frame: (%4;%5;%6)."
|
||||
).arg(params->channel_layout
|
||||
).arg(params->channels
|
||||
).arg(params->sample_fmt
|
||||
).arg(_frame->channel_layout
|
||||
).arg(_frame->channels
|
||||
).arg(_frame->format
|
||||
));
|
||||
return ReadResult::Error;
|
||||
} else {
|
||||
const auto key = "ffmpeg_" + std::to_string(ptrdiff_t(this));
|
||||
const auto value = QString("codec: (%1;%2;%3), frame: (%4;%5;%6), ptrs: (%7;%8;%9)"
|
||||
).arg(params->channel_layout
|
||||
).arg(params->channels
|
||||
).arg(params->sample_fmt
|
||||
).arg(_frame->channel_layout
|
||||
).arg(_frame->channels
|
||||
).arg(_frame->format
|
||||
).arg(ptrdiff_t(_frame->data[0])
|
||||
).arg(ptrdiff_t(_frame->extended_data[0])
|
||||
).arg(ptrdiff_t(_frame->data[1])
|
||||
);
|
||||
CrashReports::SetAnnotation(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
if ((res = swr_convert(_swrContext, _dstSamplesData, dstSamples, (const uint8_t**)_frame->extended_data, _frame->nb_samples)) < 0) {
|
||||
char err[AV_ERROR_MAX_STRING_SIZE] = { 0 };
|
||||
LOG(("Audio Error: Unable to swr_convert for file '%1', data size '%2', error %3, %4").arg(_file.name()).arg(_data.size()).arg(res).arg(av_make_error_string(err, sizeof(err), res)));
|
||||
return ReadResult::Error;
|
||||
}
|
||||
|
||||
if (_frame->extended_data[1] == nullptr) {
|
||||
const auto key = "ffmpeg_" + std::to_string(ptrdiff_t(this));
|
||||
CrashReports::ClearAnnotation(key);
|
||||
}
|
||||
|
||||
int32 resultLen = av_samples_get_buffer_size(0, AudioToChannels, res, AudioToFormat, 1);
|
||||
result.append((const char*)_dstSamplesData[0], resultLen);
|
||||
samplesAdded += resultLen / _sampleSize;
|
||||
|
||||
@@ -75,7 +75,9 @@ struct Messenger::Private {
|
||||
base::Timer quitTimer;
|
||||
};
|
||||
|
||||
Messenger::Messenger() : QObject()
|
||||
Messenger::Messenger(not_null<Core::Launcher*> launcher)
|
||||
: QObject()
|
||||
, _launcher(launcher)
|
||||
, _private(std::make_unique<Private>())
|
||||
, _langpack(std::make_unique<Lang::Instance>())
|
||||
, _audio(std::make_unique<Media::Audio::Instance>())
|
||||
|
||||
@@ -24,6 +24,17 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||
#include "mtproto/auth_key.h"
|
||||
#include "base/timer.h"
|
||||
|
||||
class AuthSession;
|
||||
class AuthSessionData;
|
||||
class MainWidget;
|
||||
class FileUploader;
|
||||
class Translator;
|
||||
class MediaView;
|
||||
|
||||
namespace Core {
|
||||
class Launcher;
|
||||
} // namespace Core
|
||||
|
||||
namespace App {
|
||||
void quit();
|
||||
} // namespace App
|
||||
@@ -36,13 +47,6 @@ using AuthKeyPtr = std::shared_ptr<AuthKey>;
|
||||
using AuthKeysList = std::vector<AuthKeyPtr>;
|
||||
} // namespace MTP
|
||||
|
||||
class AuthSession;
|
||||
class AuthSessionData;
|
||||
class MainWidget;
|
||||
class FileUploader;
|
||||
class Translator;
|
||||
class MediaView;
|
||||
|
||||
namespace Media {
|
||||
namespace Audio {
|
||||
class Instance;
|
||||
@@ -59,13 +63,17 @@ class Messenger final : public QObject, public RPCSender, private base::Subscrib
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
Messenger();
|
||||
Messenger(not_null<Core::Launcher*> launcher);
|
||||
|
||||
Messenger(const Messenger &other) = delete;
|
||||
Messenger &operator=(const Messenger &other) = delete;
|
||||
|
||||
~Messenger();
|
||||
|
||||
not_null<Core::Launcher*> launcher() const {
|
||||
return _launcher;
|
||||
}
|
||||
|
||||
// Windows interface.
|
||||
MainWindow *getActiveWindow() const;
|
||||
bool closeActiveWindow();
|
||||
@@ -220,6 +228,8 @@ private:
|
||||
|
||||
void loggedOut();
|
||||
|
||||
not_null<Core::Launcher*> _launcher;
|
||||
|
||||
QMap<FullMsgId, PeerId> photoUpdates;
|
||||
|
||||
QMap<MTP::DcId, TimeMs> killDownloadSessionTimes;
|
||||
|
||||
@@ -45,6 +45,15 @@ constexpr auto kMaxModExpSize = 256;
|
||||
// Don't try to handle messages larger than this size.
|
||||
constexpr auto kMaxMessageLength = 16 * 1024 * 1024;
|
||||
|
||||
QString LogIdsVector(const QVector<MTPlong> &ids) {
|
||||
if (!ids.size()) return "[]";
|
||||
auto idsStr = QString("[%1").arg(ids.cbegin()->v);
|
||||
for (const auto &id : ids) {
|
||||
idsStr += QString(", %2").arg(id.v);
|
||||
}
|
||||
return idsStr + "]";
|
||||
}
|
||||
|
||||
bool IsGoodModExpFirst(const openssl::BigNum &modexp, const openssl::BigNum &prime) {
|
||||
auto diff = prime - modexp;
|
||||
if (modexp.failed() || prime.failed() || diff.failed()) {
|
||||
@@ -1432,7 +1441,7 @@ void ConnectionPrivate::handleReceived() {
|
||||
// send acks
|
||||
uint32 toAckSize = ackRequestData.size();
|
||||
if (toAckSize) {
|
||||
DEBUG_LOG(("MTP Info: will send %1 acks, ids: %2").arg(toAckSize).arg(Logs::vector(ackRequestData)));
|
||||
DEBUG_LOG(("MTP Info: will send %1 acks, ids: %2").arg(toAckSize).arg(LogIdsVector(ackRequestData)));
|
||||
emit sendAnythingAsync(MTPAckSendWaiting);
|
||||
}
|
||||
|
||||
@@ -1546,7 +1555,7 @@ ConnectionPrivate::HandleResult ConnectionPrivate::handleOneReceived(const mtpPr
|
||||
auto &ids = msg.c_msgs_ack().vmsg_ids.v;
|
||||
uint32 idsCount = ids.size();
|
||||
|
||||
DEBUG_LOG(("Message Info: acks received, ids: %1").arg(Logs::vector(ids)));
|
||||
DEBUG_LOG(("Message Info: acks received, ids: %1").arg(LogIdsVector(ids)));
|
||||
if (!idsCount) return (badTime ? HandleResult::Ignored : HandleResult::Success);
|
||||
|
||||
if (badTime) {
|
||||
@@ -1676,7 +1685,7 @@ ConnectionPrivate::HandleResult ConnectionPrivate::handleOneReceived(const mtpPr
|
||||
msg.read(from, end);
|
||||
auto &ids = msg.c_msgs_state_req().vmsg_ids.v;
|
||||
auto idsCount = ids.size();
|
||||
DEBUG_LOG(("Message Info: msgs_state_req received, ids: %1").arg(Logs::vector(ids)));
|
||||
DEBUG_LOG(("Message Info: msgs_state_req received, ids: %1").arg(LogIdsVector(ids)));
|
||||
if (!idsCount) return HandleResult::Success;
|
||||
|
||||
QByteArray info(idsCount, Qt::Uninitialized);
|
||||
@@ -1787,7 +1796,7 @@ ConnectionPrivate::HandleResult ConnectionPrivate::handleOneReceived(const mtpPr
|
||||
|
||||
QVector<MTPlong> toAck;
|
||||
|
||||
DEBUG_LOG(("Message Info: msgs all info received, msgId %1, reqMsgIds: %2, states %3").arg(msgId).arg(Logs::vector(ids)).arg(Logs::mb(states.data(), states.length()).str()));
|
||||
DEBUG_LOG(("Message Info: msgs all info received, msgId %1, reqMsgIds: %2, states %3").arg(msgId).arg(LogIdsVector(ids)).arg(Logs::mb(states.data(), states.length()).str()));
|
||||
handleMsgsStates(ids, states, toAck);
|
||||
|
||||
requestsAcked(toAck);
|
||||
@@ -1856,7 +1865,7 @@ ConnectionPrivate::HandleResult ConnectionPrivate::handleOneReceived(const mtpPr
|
||||
auto &ids = msg.c_msg_resend_req().vmsg_ids.v;
|
||||
|
||||
auto idsCount = ids.size();
|
||||
DEBUG_LOG(("Message Info: resend of msgs requested, ids: %1").arg(Logs::vector(ids)));
|
||||
DEBUG_LOG(("Message Info: resend of msgs requested, ids: %1").arg(LogIdsVector(ids)));
|
||||
if (!idsCount) return (badTime ? HandleResult::Ignored : HandleResult::Success);
|
||||
|
||||
QVector<quint64> toResend(ids.size());
|
||||
@@ -2087,7 +2096,7 @@ bool ConnectionPrivate::requestsFixTimeSalt(const QVector<MTPlong> &ids, int32 s
|
||||
void ConnectionPrivate::requestsAcked(const QVector<MTPlong> &ids, bool byResponse) {
|
||||
uint32 idsCount = ids.size();
|
||||
|
||||
DEBUG_LOG(("Message Info: requests acked, ids %1").arg(Logs::vector(ids)));
|
||||
DEBUG_LOG(("Message Info: requests acked, ids %1").arg(LogIdsVector(ids)));
|
||||
|
||||
RPCCallbackClears clearedAcked;
|
||||
QVector<MTPlong> toAckMore;
|
||||
|
||||
@@ -246,7 +246,7 @@ mtpRequestId Session::send(const TRequest &request, RPCResponseHandler callbacks
|
||||
sendPrepared(reqSerialized, msCanWait);
|
||||
} catch (Exception &e) {
|
||||
requestId = 0;
|
||||
rpcErrorOccured(requestId, callbacks.onFail, rpcClientError("NO_REQUEST_ID", QString("send() failed to queue request, exception: %1").arg(e.what())));
|
||||
requestPrepareFailed(callbacks.onFail, e);
|
||||
}
|
||||
if (requestId) registerRequest(requestId, toMainDC ? -getDcWithShift() : getDcWithShift());
|
||||
return requestId;
|
||||
|
||||
@@ -23,9 +23,22 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||
#include "mtproto/connection.h"
|
||||
#include "mtproto/dcenter.h"
|
||||
#include "mtproto/auth_key.h"
|
||||
#include "core/crash_reports.h"
|
||||
|
||||
namespace MTP {
|
||||
namespace internal {
|
||||
namespace {
|
||||
|
||||
QString LogIds(const QVector<uint64> &ids) {
|
||||
if (!ids.size()) return "[]";
|
||||
auto idsStr = QString("[%1").arg(*ids.cbegin());
|
||||
for (const auto id : ids) {
|
||||
idsStr += QString(", %2").arg(id);
|
||||
}
|
||||
return idsStr + "]";
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void SessionData::setKey(const AuthKeyPtr &key) {
|
||||
if (_authKey != key) {
|
||||
@@ -140,6 +153,23 @@ bool Session::rpcErrorOccured(mtpRequestId requestId, const RPCFailHandlerPtr &o
|
||||
return _instance->rpcErrorOccured(requestId, onFail, err);
|
||||
}
|
||||
|
||||
void Session::requestPrepareFailed(
|
||||
const RPCFailHandlerPtr &onFail,
|
||||
Exception &e) {
|
||||
CrashReports::SetAnnotation("RequestException", QString::fromLatin1(e.what()));
|
||||
Unexpected("Exception in Session::send()");
|
||||
|
||||
const auto requestId = 0;
|
||||
const auto error = rpcClientError(
|
||||
"NO_REQUEST_ID",
|
||||
QString(
|
||||
"send() failed to queue request, exception: %1"
|
||||
).arg(
|
||||
e.what()
|
||||
));
|
||||
rpcErrorOccured(requestId, onFail, error);
|
||||
}
|
||||
|
||||
void Session::restart() {
|
||||
if (_killed) {
|
||||
DEBUG_LOG(("Session Error: can't restart a killed session"));
|
||||
@@ -271,7 +301,7 @@ void Session::checkRequestsByTimer() {
|
||||
}
|
||||
|
||||
if (stateRequestIds.size()) {
|
||||
DEBUG_LOG(("MTP Info: requesting state of msgs: %1").arg(Logs::vector(stateRequestIds)));
|
||||
DEBUG_LOG(("MTP Info: requesting state of msgs: %1").arg(LogIds(stateRequestIds)));
|
||||
{
|
||||
QWriteLocker locker(data.stateRequestMutex());
|
||||
for (uint32 i = 0, l = stateRequestIds.size(); i < l; ++i) {
|
||||
|
||||
@@ -356,6 +356,7 @@ private:
|
||||
mtpRequestId storeRequest(mtpRequest &request, const RPCResponseHandler &parser);
|
||||
mtpRequest getRequest(mtpRequestId requestId);
|
||||
bool rpcErrorOccured(mtpRequestId requestId, const RPCFailHandlerPtr &onFail, const RPCError &err);
|
||||
void requestPrepareFailed(const RPCFailHandlerPtr &onFail, Exception &e);
|
||||
|
||||
not_null<Instance*> _instance;
|
||||
std::unique_ptr<Connection> _connection;
|
||||
|
||||
117
Telegram/SourceFiles/platform/linux/launcher_linux.cpp
Normal file
117
Telegram/SourceFiles/platform/linux/launcher_linux.cpp
Normal file
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop version of Telegram messaging app, see https://telegram.org
|
||||
|
||||
Telegram Desktop is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
It is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
In addition, as a special exception, the copyright holders give permission
|
||||
to link the code of portions of this program with the OpenSSL library.
|
||||
|
||||
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||
Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||
*/
|
||||
#include "platform/linux/launcher_linux.h"
|
||||
|
||||
#include "core/crash_reports.h"
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <cstdlib>
|
||||
#include <unistd.h>
|
||||
#include <dirent.h>
|
||||
#include <pwd.h>
|
||||
|
||||
namespace Platform {
|
||||
namespace {
|
||||
|
||||
class Arguments {
|
||||
public:
|
||||
void push(QByteArray argument) {
|
||||
argument.append(char(0));
|
||||
_argumentValues.push_back(argument);
|
||||
_arguments.push_back(_argumentValues.back().data());
|
||||
}
|
||||
|
||||
char **result() {
|
||||
_arguments.push_back(nullptr);
|
||||
return _arguments.data();
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<QByteArray> _argumentValues;
|
||||
std::vector<char*> _arguments;
|
||||
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
bool Launcher::launchUpdater(UpdaterLaunch action) {
|
||||
if (cExeName().isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto binaryName = (action == UpdaterLaunch::JustRelaunch)
|
||||
? cExeName()
|
||||
: QStringLiteral("Updater");
|
||||
|
||||
auto argumentsList = Arguments();
|
||||
argumentsList.push(QFile::encodeName(cExeDir() + binaryName));
|
||||
|
||||
if (cLaunchMode() == LaunchModeAutoStart) {
|
||||
argumentsList.push("-autostart");
|
||||
}
|
||||
if (cDebug()) {
|
||||
argumentsList.push("-debug");
|
||||
}
|
||||
if (cStartInTray()) {
|
||||
argumentsList.push("-startintray");
|
||||
}
|
||||
if (cTestMode()) {
|
||||
argumentsList.push("-testmode");
|
||||
}
|
||||
if (cDataFile() != qsl("data")) {
|
||||
argumentsList.push("-key");
|
||||
argumentsList.push(QFile::encodeName(cDataFile()));
|
||||
}
|
||||
|
||||
if (action == UpdaterLaunch::JustRelaunch) {
|
||||
argumentsList.push("-noupdate");
|
||||
argumentsList.push("-tosettings");
|
||||
if (customWorkingDir()) {
|
||||
argumentsList.push("-workdir");
|
||||
argumentsList.push(QFile::encodeName(cWorkingDir()));
|
||||
}
|
||||
} else {
|
||||
argumentsList.push("-workpath");
|
||||
argumentsList.push(QFile::encodeName(cWorkingDir()));
|
||||
argumentsList.push("-exename");
|
||||
argumentsList.push(QFile::encodeName(cExeName()));
|
||||
argumentsList.push("-exepath");
|
||||
argumentsList.push(QFile::encodeName(cExeDir()));
|
||||
if (customWorkingDir()) {
|
||||
argumentsList.push("-workdir_custom");
|
||||
}
|
||||
}
|
||||
|
||||
Logs::closeMain();
|
||||
CrashReports::Finish();
|
||||
|
||||
const auto args = argumentsList.result();
|
||||
|
||||
pid_t pid = fork();
|
||||
switch (pid) {
|
||||
case -1: return false;
|
||||
case 0: execv(args[0], args); return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
36
Telegram/SourceFiles/platform/linux/launcher_linux.h
Normal file
36
Telegram/SourceFiles/platform/linux/launcher_linux.h
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop version of Telegram messaging app, see https://telegram.org
|
||||
|
||||
Telegram Desktop is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
It is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
In addition, as a special exception, the copyright holders give permission
|
||||
to link the code of portions of this program with the OpenSSL library.
|
||||
|
||||
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||
Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "core/launcher.h"
|
||||
|
||||
namespace Platform {
|
||||
|
||||
class Launcher : public Core::Launcher {
|
||||
public:
|
||||
using Core::Launcher::Launcher;
|
||||
|
||||
private:
|
||||
bool launchUpdater(UpdaterLaunch action) override;
|
||||
|
||||
};
|
||||
|
||||
} // namespace Platform
|
||||
@@ -25,6 +25,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||
#include "platform/linux/file_utilities_linux.h"
|
||||
#include "platform/platform_notifications_manager.h"
|
||||
#include "storage/localstorage.h"
|
||||
#include "core/crash_reports.h"
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
@@ -525,98 +526,6 @@ void psNewVersion() {
|
||||
psRegisterCustomScheme();
|
||||
}
|
||||
|
||||
bool _execUpdater(bool update = true, const QString &crashreport = QString()) {
|
||||
if (cExeName().isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
static const int MaxLen = 65536, MaxArgsCount = 128;
|
||||
|
||||
char path[MaxLen] = {0};
|
||||
QByteArray data(QFile::encodeName(cExeDir() + (update ? "Updater" : cExeName())));
|
||||
memcpy(path, data.constData(), data.size());
|
||||
|
||||
char *args[MaxArgsCount] = { 0 };
|
||||
char p_noupdate[] = "-noupdate";
|
||||
char p_autostart[] = "-autostart";
|
||||
char p_debug[] = "-debug";
|
||||
char p_tosettings[] = "-tosettings";
|
||||
char p_key[] = "-key";
|
||||
char p_datafile[MaxLen] = { 0 };
|
||||
char p_path[] = "-workpath";
|
||||
char p_pathbuf[MaxLen] = { 0 };
|
||||
char p_startintray[] = "-startintray";
|
||||
char p_testmode[] = "-testmode";
|
||||
char p_crashreport[] = "-crashreport";
|
||||
char p_crashreportbuf[MaxLen] = { 0 };
|
||||
char p_exe[] = "-exename";
|
||||
char p_exebuf[MaxLen] = { 0 };
|
||||
char p_exepath[] = "-exepath";
|
||||
char p_exepathbuf[MaxLen] = { 0 };
|
||||
int argIndex = 0;
|
||||
args[argIndex++] = path;
|
||||
if (!update) {
|
||||
args[argIndex++] = p_noupdate;
|
||||
args[argIndex++] = p_tosettings;
|
||||
}
|
||||
if (cLaunchMode() == LaunchModeAutoStart) args[argIndex++] = p_autostart;
|
||||
if (cDebug()) args[argIndex++] = p_debug;
|
||||
if (cStartInTray()) args[argIndex++] = p_startintray;
|
||||
if (cTestMode()) args[argIndex++] = p_testmode;
|
||||
if (cDataFile() != qsl("data")) {
|
||||
QByteArray dataf = QFile::encodeName(cDataFile());
|
||||
if (dataf.size() < MaxLen) {
|
||||
memcpy(p_datafile, dataf.constData(), dataf.size());
|
||||
args[argIndex++] = p_key;
|
||||
args[argIndex++] = p_datafile;
|
||||
}
|
||||
}
|
||||
QByteArray pathf = QFile::encodeName(cWorkingDir());
|
||||
if (pathf.size() < MaxLen) {
|
||||
memcpy(p_pathbuf, pathf.constData(), pathf.size());
|
||||
args[argIndex++] = p_path;
|
||||
args[argIndex++] = p_pathbuf;
|
||||
}
|
||||
if (!crashreport.isEmpty()) {
|
||||
QByteArray crashreportf = QFile::encodeName(crashreport);
|
||||
if (crashreportf.size() < MaxLen) {
|
||||
memcpy(p_crashreportbuf, crashreportf.constData(), crashreportf.size());
|
||||
args[argIndex++] = p_crashreport;
|
||||
args[argIndex++] = p_crashreportbuf;
|
||||
}
|
||||
}
|
||||
QByteArray exef = QFile::encodeName(cExeName());
|
||||
if (exef.size() > 0 && exef.size() < MaxLen) {
|
||||
memcpy(p_exebuf, exef.constData(), exef.size());
|
||||
args[argIndex++] = p_exe;
|
||||
args[argIndex++] = p_exebuf;
|
||||
}
|
||||
QByteArray exepathf = QFile::encodeName(cExeDir());
|
||||
if (exepathf.size() > 0 && exepathf.size() < MaxLen) {
|
||||
memcpy(p_exepathbuf, exepathf.constData(), exepathf.size());
|
||||
args[argIndex++] = p_exepath;
|
||||
args[argIndex++] = p_exepathbuf;
|
||||
}
|
||||
|
||||
Logs::closeMain();
|
||||
SignalHandlers::finish();
|
||||
pid_t pid = fork();
|
||||
switch (pid) {
|
||||
case -1: return false;
|
||||
case 0: execv(path, args); return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void psExecUpdater() {
|
||||
if (!_execUpdater()) {
|
||||
psDeleteDir(cWorkingDir() + qsl("tupdates/temp"));
|
||||
}
|
||||
}
|
||||
|
||||
void psExecTelegram(const QString &crashreport) {
|
||||
_execUpdater(false, crashreport);
|
||||
}
|
||||
|
||||
bool psShowOpenWithMenu(int x, int y, const QString &file) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -77,9 +77,6 @@ void psBringToBack(QWidget *w);
|
||||
int psCleanup();
|
||||
int psFixPrevious();
|
||||
|
||||
void psExecUpdater();
|
||||
void psExecTelegram(const QString &arg = QString());
|
||||
|
||||
QAbstractNativeEventFilter *psNativeEventFilter();
|
||||
|
||||
void psNewVersion();
|
||||
|
||||
38
Telegram/SourceFiles/platform/mac/launcher_mac.h
Normal file
38
Telegram/SourceFiles/platform/mac/launcher_mac.h
Normal file
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop version of Telegram messaging app, see https://telegram.org
|
||||
|
||||
Telegram Desktop is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
It is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
In addition, as a special exception, the copyright holders give permission
|
||||
to link the code of portions of this program with the OpenSSL library.
|
||||
|
||||
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||
Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "core/launcher.h"
|
||||
|
||||
namespace Platform {
|
||||
|
||||
class Launcher : public Core::Launcher {
|
||||
public:
|
||||
using Core::Launcher::Launcher;
|
||||
|
||||
private:
|
||||
void initHook() override;
|
||||
|
||||
bool launchUpdater(UpdaterLaunch action) override;
|
||||
|
||||
};
|
||||
|
||||
} // namespace Platform
|
||||
98
Telegram/SourceFiles/platform/mac/launcher_mac.mm
Normal file
98
Telegram/SourceFiles/platform/mac/launcher_mac.mm
Normal file
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop version of Telegram messaging app, see https://telegram.org
|
||||
|
||||
Telegram Desktop is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
It is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
In addition, as a special exception, the copyright holders give permission
|
||||
to link the code of portions of this program with the OpenSSL library.
|
||||
|
||||
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||
Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||
*/
|
||||
#include "platform/mac/launcher_mac.h"
|
||||
|
||||
#include "core/crash_reports.h"
|
||||
#include "platform/mac/mac_utilities.h"
|
||||
|
||||
#include <Cocoa/Cocoa.h>
|
||||
#include <CoreFoundation/CFURL.h>
|
||||
|
||||
namespace Platform {
|
||||
|
||||
void Launcher::initHook() {
|
||||
#ifndef OS_MAC_OLD
|
||||
// macOS Retina display support is working fine, others are not.
|
||||
QCoreApplication::setAttribute(Qt::AA_DisableHighDpiScaling, false);
|
||||
#endif // OS_MAC_OLD
|
||||
}
|
||||
|
||||
bool Launcher::launchUpdater(UpdaterLaunch action) {
|
||||
if (cExeName().isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
@autoreleasepool {
|
||||
|
||||
#ifdef OS_MAC_STORE
|
||||
// In AppStore version we don't have Updater.
|
||||
// We just relaunch our app.
|
||||
if (action == UpdaterLaunch::JustRelaunch) {
|
||||
NSDictionary *conf = [NSDictionary dictionaryWithObject:[NSArray array] forKey:NSWorkspaceLaunchConfigurationArguments];
|
||||
[[NSWorkspace sharedWorkspace] launchApplicationAtURL:[NSURL fileURLWithPath:Q2NSString(cExeDir() + cExeName())] options:NSWorkspaceLaunchAsync | NSWorkspaceLaunchNewInstance configuration:conf error:0];
|
||||
return true;
|
||||
}
|
||||
#endif // OS_MAC_STORE
|
||||
|
||||
NSString *path = @"", *args = @"";
|
||||
@try {
|
||||
path = [[NSBundle mainBundle] bundlePath];
|
||||
if (!path) {
|
||||
LOG(("Could not get bundle path!!"));
|
||||
return false;
|
||||
}
|
||||
path = [path stringByAppendingString:@"/Contents/Frameworks/Updater"];
|
||||
|
||||
NSMutableArray *args = [[NSMutableArray alloc] initWithObjects:@"-workpath", Q2NSString(cWorkingDir()), @"-procid", nil];
|
||||
[args addObject:[NSString stringWithFormat:@"%d", [[NSProcessInfo processInfo] processIdentifier]]];
|
||||
if (cRestartingToSettings()) [args addObject:@"-tosettings"];
|
||||
if (action == UpdaterLaunch::JustRelaunch) [args addObject:@"-noupdate"];
|
||||
if (cLaunchMode() == LaunchModeAutoStart) [args addObject:@"-autostart"];
|
||||
if (cDebug()) [args addObject:@"-debug"];
|
||||
if (cStartInTray()) [args addObject:@"-startintray"];
|
||||
if (cTestMode()) [args addObject:@"-testmode"];
|
||||
if (cDataFile() != qsl("data")) {
|
||||
[args addObject:@"-key"];
|
||||
[args addObject:Q2NSString(cDataFile())];
|
||||
}
|
||||
if (customWorkingDir()) {
|
||||
[args addObject:@"-workdir_custom"];
|
||||
}
|
||||
|
||||
DEBUG_LOG(("Application Info: executing %1 %2").arg(NS2QString(path)).arg(NS2QString([args componentsJoinedByString:@" "])));
|
||||
Logs::closeMain();
|
||||
CrashReports::Finish();
|
||||
if (![NSTask launchedTaskWithLaunchPath:path arguments:args]) {
|
||||
DEBUG_LOG(("Task not launched while executing %1 %2").arg(NS2QString(path)).arg(NS2QString([args componentsJoinedByString:@" "])));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@catch (NSException *exception) {
|
||||
LOG(("Exception caught while executing %1 %2").arg(NS2QString(path)).arg(NS2QString(args)));
|
||||
return false;
|
||||
}
|
||||
@finally {
|
||||
}
|
||||
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace Platform
|
||||
@@ -38,6 +38,20 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||
#include <IOKit/hidsystem/ev_keymap.h>
|
||||
#include <SPMediaKeyTap.h>
|
||||
|
||||
@interface MainWindowObserver : NSObject {
|
||||
}
|
||||
|
||||
- (id) init:(MainWindow::Private*)window;
|
||||
- (void) activeSpaceDidChange:(NSNotification *)aNotification;
|
||||
- (void) darkModeChanged:(NSNotification *)aNotification;
|
||||
- (void) screenIsLocked:(NSNotification *)aNotification;
|
||||
- (void) screenIsUnlocked:(NSNotification *)aNotification;
|
||||
- (void) windowWillEnterFullScreen:(NSNotification *)aNotification;
|
||||
- (void) windowWillExitFullScreen:(NSNotification *)aNotification;
|
||||
|
||||
@end // @interface MainWindowObserver
|
||||
|
||||
namespace Platform {
|
||||
namespace {
|
||||
|
||||
// When we close a window that is fullscreen we first leave the fullscreen
|
||||
@@ -56,23 +70,34 @@ id FindClassInSubviews(NSView *parent, NSString *className) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
#ifndef OS_MAC_OLD
|
||||
|
||||
class LayerCreationChecker : public QObject {
|
||||
public:
|
||||
LayerCreationChecker(NSView * __weak view, base::lambda<void()> callback)
|
||||
: _weakView(view)
|
||||
, _callback(std::move(callback)) {
|
||||
QCoreApplication::instance()->installEventFilter(this);
|
||||
}
|
||||
|
||||
protected:
|
||||
bool eventFilter(QObject *object, QEvent *event) override {
|
||||
if (!_weakView || [_weakView layer] != nullptr) {
|
||||
_callback();
|
||||
}
|
||||
return QObject::eventFilter(object, event);
|
||||
}
|
||||
|
||||
private:
|
||||
NSView * __weak _weakView = nil;
|
||||
base::lambda<void()> _callback;
|
||||
|
||||
};
|
||||
|
||||
#endif // OS_MAC_OLD
|
||||
|
||||
} // namespace
|
||||
|
||||
@interface MainWindowObserver : NSObject {
|
||||
}
|
||||
|
||||
- (id) init:(MainWindow::Private*)window;
|
||||
- (void) activeSpaceDidChange:(NSNotification *)aNotification;
|
||||
- (void) darkModeChanged:(NSNotification *)aNotification;
|
||||
- (void) screenIsLocked:(NSNotification *)aNotification;
|
||||
- (void) screenIsUnlocked:(NSNotification *)aNotification;
|
||||
- (void) windowWillEnterFullScreen:(NSNotification *)aNotification;
|
||||
- (void) windowWillExitFullScreen:(NSNotification *)aNotification;
|
||||
|
||||
@end // @interface MainWindowObserver
|
||||
|
||||
namespace Platform {
|
||||
|
||||
class MainWindow::Private {
|
||||
public:
|
||||
Private(MainWindow *window);
|
||||
@@ -108,6 +133,7 @@ private:
|
||||
NSView * __weak _nativeView = nil;
|
||||
id __weak _nativeTitleWrapWeak = nil;
|
||||
id __weak _nativeTitleWeak = nil;
|
||||
std::unique_ptr<LayerCreationChecker> _layerCreationChecker;
|
||||
#endif // !OS_MAC_OLD
|
||||
bool _useNativeTitle = false;
|
||||
bool _inFullScreen = false;
|
||||
@@ -220,6 +246,22 @@ void MainWindow::Private::initCustomTitle() {
|
||||
auto full = [_nativeView frame];
|
||||
_public->_customTitleHeight = qMax(qRound(full.size.height - inner.size.height), 0);
|
||||
|
||||
// Qt still has some bug with layer-backed widgets containing QOpenGLWidgets.
|
||||
// See https://github.com/telegramdesktop/tdesktop/issues/4150
|
||||
// Tried to workaround it by catching the first moment we have CALayer created
|
||||
// and explicitly setting contentsScale to window->backingScaleFactor there.
|
||||
_layerCreationChecker = std::make_unique<LayerCreationChecker>(_nativeView, [=] {
|
||||
if (_nativeView && _nativeWindow) {
|
||||
if (CALayer *layer = [_nativeView layer]) {
|
||||
LOG(("Window Info: Setting layer scale factor to: %1").arg([_nativeWindow backingScaleFactor]));
|
||||
[layer setContentsScale: [_nativeWindow backingScaleFactor]];
|
||||
_layerCreationChecker = nullptr;
|
||||
}
|
||||
} else {
|
||||
_layerCreationChecker = nullptr;
|
||||
}
|
||||
});
|
||||
|
||||
// Disabled for now.
|
||||
//_useNativeTitle = true;
|
||||
//setWindowTitle(qsl("Telegram"));
|
||||
|
||||
@@ -78,9 +78,6 @@ void psBringToBack(QWidget *w);
|
||||
int psCleanup();
|
||||
int psFixPrevious();
|
||||
|
||||
void psExecUpdater();
|
||||
void psExecTelegram(const QString &crashreport = QString());
|
||||
|
||||
bool psShowOpenWithMenu(int x, int y, const QString &file);
|
||||
|
||||
QAbstractNativeEventFilter *psNativeEventFilter();
|
||||
|
||||
@@ -17,19 +17,18 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||
*/
|
||||
#include "platform/mac/specific_mac.h"
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
#include "lang/lang_keys.h"
|
||||
#include "application.h"
|
||||
#include "mainwidget.h"
|
||||
#include "history/history_widget.h"
|
||||
|
||||
#include "core/crash_reports.h"
|
||||
#include "storage/localstorage.h"
|
||||
#include "passcodewidget.h"
|
||||
#include "mainwindow.h"
|
||||
#include "history/history_location_manager.h"
|
||||
#include "platform/mac/mac_utilities.h"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <execinfo.h>
|
||||
|
||||
#include <Cocoa/Cocoa.h>
|
||||
@@ -91,8 +90,10 @@ QAbstractNativeEventFilter *psNativeEventFilter() {
|
||||
}
|
||||
|
||||
void psWriteDump() {
|
||||
#ifndef TDESKTOP_DISABLE_CRASH_REPORTS
|
||||
double v = objc_appkitVersion();
|
||||
SignalHandlers::dump() << "OS-Version: " << v;
|
||||
CrashReports::dump() << "OS-Version: " << v;
|
||||
#endif // TDESKTOP_DISABLE_CRASH_REPORTS
|
||||
}
|
||||
|
||||
QString demanglestr(const QString &mangled) {
|
||||
@@ -413,16 +414,6 @@ void psNewVersion() {
|
||||
objc_registerCustomScheme();
|
||||
}
|
||||
|
||||
void psExecUpdater() {
|
||||
if (!objc_execUpdater()) {
|
||||
psDeleteDir(cWorkingDir() + qsl("tupdates/temp"));
|
||||
}
|
||||
}
|
||||
|
||||
void psExecTelegram(const QString &crashreport) {
|
||||
objc_execTelegram(crashreport);
|
||||
}
|
||||
|
||||
void psAutoStart(bool start, bool silent) {
|
||||
}
|
||||
|
||||
|
||||
@@ -32,8 +32,6 @@ bool objc_idleTime(TimeMs &idleTime);
|
||||
void objc_start();
|
||||
void objc_ignoreApplicationActivationRightNow();
|
||||
void objc_finish();
|
||||
bool objc_execUpdater();
|
||||
void objc_execTelegram(const QString &crashreport);
|
||||
|
||||
void objc_registerCustomScheme();
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||
#include "styles/style_window.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "base/timer.h"
|
||||
#include "core/crash_reports.h"
|
||||
|
||||
#include <Cocoa/Cocoa.h>
|
||||
#include <CoreFoundation/CFURL.h>
|
||||
@@ -410,74 +411,6 @@ void objc_registerCustomScheme() {
|
||||
#endif // !TDESKTOP_DISABLE_REGISTER_CUSTOM_SCHEME
|
||||
}
|
||||
|
||||
BOOL _execUpdater(BOOL update = YES, const QString &crashreport = QString()) {
|
||||
@autoreleasepool {
|
||||
|
||||
NSString *path = @"", *args = @"";
|
||||
@try {
|
||||
path = [[NSBundle mainBundle] bundlePath];
|
||||
if (!path) {
|
||||
LOG(("Could not get bundle path!!"));
|
||||
return NO;
|
||||
}
|
||||
path = [path stringByAppendingString:@"/Contents/Frameworks/Updater"];
|
||||
|
||||
NSMutableArray *args = [[NSMutableArray alloc] initWithObjects:@"-workpath", Q2NSString(cWorkingDir()), @"-procid", nil];
|
||||
[args addObject:[NSString stringWithFormat:@"%d", [[NSProcessInfo processInfo] processIdentifier]]];
|
||||
if (cRestartingToSettings()) [args addObject:@"-tosettings"];
|
||||
if (!update) [args addObject:@"-noupdate"];
|
||||
if (cLaunchMode() == LaunchModeAutoStart) [args addObject:@"-autostart"];
|
||||
if (cDebug()) [args addObject:@"-debug"];
|
||||
if (cStartInTray()) [args addObject:@"-startintray"];
|
||||
if (cTestMode()) [args addObject:@"-testmode"];
|
||||
if (cDataFile() != qsl("data")) {
|
||||
[args addObject:@"-key"];
|
||||
[args addObject:Q2NSString(cDataFile())];
|
||||
}
|
||||
if (!crashreport.isEmpty()) {
|
||||
[args addObject:@"-crashreport"];
|
||||
[args addObject:Q2NSString(crashreport)];
|
||||
}
|
||||
|
||||
DEBUG_LOG(("Application Info: executing %1 %2").arg(NS2QString(path)).arg(NS2QString([args componentsJoinedByString:@" "])));
|
||||
Logs::closeMain();
|
||||
SignalHandlers::finish();
|
||||
if (![NSTask launchedTaskWithLaunchPath:path arguments:args]) {
|
||||
DEBUG_LOG(("Task not launched while executing %1 %2").arg(NS2QString(path)).arg(NS2QString([args componentsJoinedByString:@" "])));
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
@catch (NSException *exception) {
|
||||
LOG(("Exception caught while executing %1 %2").arg(NS2QString(path)).arg(NS2QString(args)));
|
||||
return NO;
|
||||
}
|
||||
@finally {
|
||||
}
|
||||
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
bool objc_execUpdater() {
|
||||
return !!_execUpdater();
|
||||
}
|
||||
|
||||
void objc_execTelegram(const QString &crashreport) {
|
||||
if (cExeName().isEmpty()) {
|
||||
return;
|
||||
}
|
||||
#ifndef OS_MAC_STORE
|
||||
_execUpdater(NO, crashreport);
|
||||
#else // OS_MAC_STORE
|
||||
@autoreleasepool {
|
||||
|
||||
NSDictionary *conf = [NSDictionary dictionaryWithObject:[NSArray array] forKey:NSWorkspaceLaunchConfigurationArguments];
|
||||
[[NSWorkspace sharedWorkspace] launchApplicationAtURL:[NSURL fileURLWithPath:Q2NSString(cExeDir() + cExeName())] options:NSWorkspaceLaunchAsync | NSWorkspaceLaunchNewInstance configuration:conf error:0];
|
||||
|
||||
}
|
||||
#endif // OS_MAC_STORE
|
||||
}
|
||||
|
||||
void objc_activateProgram(WId winId) {
|
||||
[NSApp activateIgnoringOtherApps:YES];
|
||||
if (winId) {
|
||||
|
||||
43
Telegram/SourceFiles/platform/platform_launcher.h
Normal file
43
Telegram/SourceFiles/platform/platform_launcher.h
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop version of Telegram messaging app, see https://telegram.org
|
||||
|
||||
Telegram Desktop is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
It is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
In addition, as a special exception, the copyright holders give permission
|
||||
to link the code of portions of this program with the OpenSSL library.
|
||||
|
||||
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||
Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
namespace Platform {
|
||||
|
||||
//class Launcher : public Core::Launcher {
|
||||
//public:
|
||||
// using Core::Launcher::Launcher;
|
||||
//
|
||||
// ...
|
||||
//
|
||||
//};
|
||||
|
||||
} // namespace Platform
|
||||
|
||||
// Platform dependent implementations.
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
#include "platform/mac/launcher_mac.h"
|
||||
#elif defined Q_OS_LINUX // Q_OS_MAC
|
||||
#include "platform/linux/launcher_linux.h"
|
||||
#elif defined Q_OS_WINRT || defined Q_OS_WIN // Q_OS_MAC || Q_OS_LINUX
|
||||
#include "platform/win/launcher_win.h"
|
||||
#endif // Q_OS_MAC || Q_OS_LINUX || Q_OS_WINRT || Q_OS_WIN
|
||||
145
Telegram/SourceFiles/platform/win/launcher_win.cpp
Normal file
145
Telegram/SourceFiles/platform/win/launcher_win.cpp
Normal file
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop version of Telegram messaging app, see https://telegram.org
|
||||
|
||||
Telegram Desktop is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
It is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
In addition, as a special exception, the copyright holders give permission
|
||||
to link the code of portions of this program with the OpenSSL library.
|
||||
|
||||
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||
Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||
*/
|
||||
#include "platform/win/launcher_win.h"
|
||||
|
||||
#include "core/crash_reports.h"
|
||||
#include "platform/platform_specific.h"
|
||||
|
||||
#include <windows.h>
|
||||
#include <shellapi.h>
|
||||
|
||||
namespace Platform {
|
||||
|
||||
base::optional<QStringList> Launcher::readArgumentsHook(
|
||||
int argc,
|
||||
char *argv[]) const {
|
||||
auto count = 0;
|
||||
if (const auto list = CommandLineToArgvW(GetCommandLine(), &count)) {
|
||||
const auto guard = gsl::finally([&] { LocalFree(list); });
|
||||
if (count > 0) {
|
||||
auto result = QStringList();
|
||||
result.reserve(count);
|
||||
for (auto i = 0; i != count; ++i) {
|
||||
result.push_back(QString::fromWCharArray(list[i]));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return base::none;
|
||||
}
|
||||
|
||||
bool Launcher::launchUpdater(UpdaterLaunch action) {
|
||||
if (cExeName().isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto operation = (action == UpdaterLaunch::JustRelaunch)
|
||||
? QString()
|
||||
: (cWriteProtected()
|
||||
? qsl("runas")
|
||||
: QString());
|
||||
const auto binaryPath = (action == UpdaterLaunch::JustRelaunch)
|
||||
? (cExeDir() + cExeName())
|
||||
: (cWriteProtected()
|
||||
? (cWorkingDir() + qsl("tupdates/temp/Updater.exe"))
|
||||
: (cExeDir() + qsl("Updater.exe")));
|
||||
|
||||
auto argumentsList = QStringList();
|
||||
const auto pushArgument = [&](const QString &argument) {
|
||||
argumentsList.push_back(argument.trimmed());
|
||||
};
|
||||
if (cLaunchMode() == LaunchModeAutoStart) {
|
||||
pushArgument(qsl("-autostart"));
|
||||
}
|
||||
if (cDebug()) {
|
||||
pushArgument(qsl("-debug"));
|
||||
}
|
||||
if (cStartInTray()) {
|
||||
pushArgument(qsl("-startintray"));
|
||||
}
|
||||
if (cTestMode()) {
|
||||
pushArgument(qsl("-testmode"));
|
||||
}
|
||||
if (customWorkingDir()) {
|
||||
pushArgument(qsl("-workdir"));
|
||||
pushArgument('"' + cWorkingDir() + '"');
|
||||
}
|
||||
if (cDataFile() != qsl("data")) {
|
||||
pushArgument(qsl("-key"));
|
||||
pushArgument('"' + cDataFile() + '"');
|
||||
}
|
||||
|
||||
if (action == UpdaterLaunch::JustRelaunch) {
|
||||
pushArgument(qsl("-noupdate"));
|
||||
if (cRestartingToSettings()) {
|
||||
pushArgument(qsl("-tosettings"));
|
||||
}
|
||||
} else {
|
||||
pushArgument(qsl("-update"));
|
||||
pushArgument(qsl("-exename"));
|
||||
pushArgument('"' + cExeName() + '"');
|
||||
if (cWriteProtected()) {
|
||||
pushArgument(qsl("-writeprotected"));
|
||||
pushArgument('"' + cExeDir() + '"');
|
||||
}
|
||||
}
|
||||
return launch(operation, binaryPath, argumentsList);
|
||||
}
|
||||
|
||||
bool Launcher::launch(
|
||||
const QString &operation,
|
||||
const QString &binaryPath,
|
||||
const QStringList &argumentsList) {
|
||||
const auto convertPath = [](const QString &path) {
|
||||
return QDir::toNativeSeparators(path).toStdWString();
|
||||
};
|
||||
const auto nativeBinaryPath = convertPath(binaryPath);
|
||||
const auto nativeWorkingDir = convertPath(cWorkingDir());
|
||||
const auto arguments = argumentsList.join(' ');
|
||||
|
||||
DEBUG_LOG(("Application Info: executing %1 %2"
|
||||
).arg(binaryPath
|
||||
).arg(arguments
|
||||
));
|
||||
|
||||
Logs::closeMain();
|
||||
CrashReports::Finish();
|
||||
|
||||
const auto hwnd = HWND(0);
|
||||
const auto result = ShellExecute(
|
||||
hwnd,
|
||||
operation.isEmpty() ? nullptr : operation.toStdWString().c_str(),
|
||||
nativeBinaryPath.c_str(),
|
||||
arguments.toStdWString().c_str(),
|
||||
nativeWorkingDir.empty() ? nullptr : nativeWorkingDir.c_str(),
|
||||
SW_SHOWNORMAL);
|
||||
if (long(result) < 32) {
|
||||
DEBUG_LOG(("Application Error: failed to execute %1, working directory: '%2', result: %3"
|
||||
).arg(binaryPath
|
||||
).arg(cWorkingDir()
|
||||
).arg(long(result)
|
||||
));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
45
Telegram/SourceFiles/platform/win/launcher_win.h
Normal file
45
Telegram/SourceFiles/platform/win/launcher_win.h
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop version of Telegram messaging app, see https://telegram.org
|
||||
|
||||
Telegram Desktop is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
It is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
In addition, as a special exception, the copyright holders give permission
|
||||
to link the code of portions of this program with the OpenSSL library.
|
||||
|
||||
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||
Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "core/launcher.h"
|
||||
|
||||
namespace Platform {
|
||||
|
||||
class Launcher : public Core::Launcher {
|
||||
public:
|
||||
using Core::Launcher::Launcher;
|
||||
|
||||
private:
|
||||
base::optional<QStringList> readArgumentsHook(
|
||||
int argc,
|
||||
char *argv[]) const override;
|
||||
|
||||
bool launchUpdater(UpdaterLaunch action) override;
|
||||
|
||||
bool launch(
|
||||
const QString &operation,
|
||||
const QString &binaryPath,
|
||||
const QStringList &argumentsList);
|
||||
|
||||
};
|
||||
|
||||
} // namespace Platform
|
||||
@@ -32,6 +32,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||
#include "storage/localstorage.h"
|
||||
#include "passcodewidget.h"
|
||||
#include "base/task_queue.h"
|
||||
#include "core/crash_reports.h"
|
||||
|
||||
#include <Shobjidl.h>
|
||||
#include <shellapi.h>
|
||||
@@ -647,53 +648,6 @@ void psNewVersion() {
|
||||
}
|
||||
}
|
||||
|
||||
void psExecUpdater() {
|
||||
if (cExeName().isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
QString targs = qsl("-update -exename \"") + cExeName() + '"';
|
||||
if (cLaunchMode() == LaunchModeAutoStart) targs += qsl(" -autostart");
|
||||
if (cDebug()) targs += qsl(" -debug");
|
||||
if (cStartInTray()) targs += qsl(" -startintray");
|
||||
if (cWriteProtected()) targs += qsl(" -writeprotected \"") + cExeDir() + '"';
|
||||
|
||||
QString updaterPath = cWriteProtected() ? (cWorkingDir() + qsl("tupdates/temp/Updater.exe")) : (cExeDir() + qsl("Updater.exe"));
|
||||
|
||||
QString updater(QDir::toNativeSeparators(updaterPath)), wdir(QDir::toNativeSeparators(cWorkingDir()));
|
||||
|
||||
DEBUG_LOG(("Application Info: executing %1 %2").arg(cExeDir() + "Updater.exe").arg(targs));
|
||||
HINSTANCE r = ShellExecute(0, cWriteProtected() ? L"runas" : 0, updater.toStdWString().c_str(), targs.toStdWString().c_str(), wdir.isEmpty() ? 0 : wdir.toStdWString().c_str(), SW_SHOWNORMAL);
|
||||
if (long(r) < 32) {
|
||||
DEBUG_LOG(("Application Error: failed to execute %1, working directory: '%2', result: %3").arg(updater).arg(wdir).arg(long(r)));
|
||||
psDeleteDir(cWorkingDir() + qsl("tupdates/temp"));
|
||||
}
|
||||
}
|
||||
|
||||
void psExecTelegram(const QString &crashreport) {
|
||||
if (cExeName().isEmpty()) {
|
||||
return;
|
||||
}
|
||||
QString targs = crashreport.isEmpty() ? qsl("-noupdate") : ('"' + crashreport + '"');
|
||||
if (crashreport.isEmpty()) {
|
||||
if (cRestartingToSettings()) targs += qsl(" -tosettings");
|
||||
if (cLaunchMode() == LaunchModeAutoStart) targs += qsl(" -autostart");
|
||||
if (cDebug()) targs += qsl(" -debug");
|
||||
if (cStartInTray()) targs += qsl(" -startintray");
|
||||
if (cTestMode()) targs += qsl(" -testmode");
|
||||
if (cDataFile() != qsl("data")) targs += qsl(" -key \"") + cDataFile() + '"';
|
||||
}
|
||||
QString telegram(QDir::toNativeSeparators(cExeDir() + cExeName())), wdir(QDir::toNativeSeparators(cWorkingDir()));
|
||||
|
||||
DEBUG_LOG(("Application Info: executing %1 %2").arg(cExeDir() + cExeName()).arg(targs));
|
||||
Logs::closeMain();
|
||||
SignalHandlers::finish();
|
||||
HINSTANCE r = ShellExecute(0, 0, telegram.toStdWString().c_str(), targs.toStdWString().c_str(), wdir.isEmpty() ? 0 : wdir.toStdWString().c_str(), SW_SHOWNORMAL);
|
||||
if (long(r) < 32) {
|
||||
DEBUG_LOG(("Application Error: failed to execute %1, working directory: '%2', result: %3").arg(telegram).arg(wdir).arg(long(r)));
|
||||
}
|
||||
}
|
||||
|
||||
void _manageAppLnk(bool create, bool silent, int path_csidl, const wchar_t *args, const wchar_t *description) {
|
||||
if (cExeName().isEmpty()) {
|
||||
return;
|
||||
@@ -1291,7 +1245,7 @@ QString psPrepareCrashDump(const QByteArray &crashdump, QString dumpfile) {
|
||||
void psWriteStackTrace() {
|
||||
#ifndef TDESKTOP_DISABLE_CRASH_REPORTS
|
||||
if (!LoadDbgHelp()) {
|
||||
SignalHandlers::dump() << "ERROR: Could not load dbghelp.dll!\n";
|
||||
CrashReports::dump() << "ERROR: Could not load dbghelp.dll!\n";
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1348,17 +1302,17 @@ void psWriteStackTrace() {
|
||||
// deeper frame could not be found.
|
||||
// CONTEXT need not to be suplied if imageTyp is IMAGE_FILE_MACHINE_I386!
|
||||
if (!stackWalk64(imageType, hProcess, hThread, &s, &c, ReadProcessMemoryRoutine64, symFunctionTableAccess64, symGetModuleBase64, NULL)) {
|
||||
SignalHandlers::dump() << "ERROR: Call to StackWalk64() failed!\n";
|
||||
CrashReports::dump() << "ERROR: Call to StackWalk64() failed!\n";
|
||||
return;
|
||||
}
|
||||
|
||||
if (s.AddrPC.Offset == s.AddrReturn.Offset) {
|
||||
SignalHandlers::dump() << s.AddrPC.Offset << "\n";
|
||||
SignalHandlers::dump() << "ERROR: StackWalk64() endless callstack!";
|
||||
CrashReports::dump() << s.AddrPC.Offset << "\n";
|
||||
CrashReports::dump() << "ERROR: StackWalk64() endless callstack!";
|
||||
return;
|
||||
}
|
||||
if (s.AddrPC.Offset != 0) { // we seem to have a valid PC
|
||||
SignalHandlers::dump() << s.AddrPC.Offset << "\n";
|
||||
CrashReports::dump() << s.AddrPC.Offset << "\n";
|
||||
}
|
||||
|
||||
if (s.AddrReturn.Offset == 0) {
|
||||
|
||||
@@ -90,9 +90,6 @@ void psBringToBack(QWidget *w);
|
||||
int psCleanup();
|
||||
int psFixPrevious();
|
||||
|
||||
void psExecUpdater();
|
||||
void psExecTelegram(const QString &arg = QString());
|
||||
|
||||
QAbstractNativeEventFilter *psNativeEventFilter();
|
||||
|
||||
void psNewVersion();
|
||||
|
||||
@@ -20,14 +20,9 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||
*/
|
||||
#include "settings.h"
|
||||
|
||||
#include "platform/platform_specific.h"
|
||||
#include "data/data_document.h"
|
||||
|
||||
bool gRtl = false;
|
||||
Qt::LayoutDirection gLangDir = gRtl ? Qt::RightToLeft : Qt::LeftToRight;
|
||||
|
||||
QString gArguments;
|
||||
|
||||
bool gAlphaVersion = AppAlphaVersion;
|
||||
uint64 gBetaVersion = AppBetaVersion;
|
||||
uint64 gRealBetaVersion = AppBetaVersion;
|
||||
@@ -66,7 +61,9 @@ uint32 gConnectionsInSession = 1;
|
||||
QString gLoggedPhoneNumber;
|
||||
|
||||
QByteArray gLocalSalt;
|
||||
DBIScale gRealScale = dbisAuto, gScreenScale = dbisOne, gConfigScale = dbisAuto;
|
||||
DBIScale gRealScale = dbisAuto;
|
||||
DBIScale gScreenScale = dbisOne;
|
||||
DBIScale gConfigScale = dbisAuto;
|
||||
bool gCompressPastedImage = true;
|
||||
|
||||
QString gTimeFormat = qsl("hh:mm");
|
||||
@@ -92,6 +89,8 @@ int32 gIntRetinaFactor = 1;
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
DBIPlatform gPlatform = dbipWindows;
|
||||
#elif defined OS_MAC_OLD
|
||||
DBIPlatform gPlatform = dbipMacOld;
|
||||
#elif defined Q_OS_MAC
|
||||
DBIPlatform gPlatform = dbipMac;
|
||||
#elif defined Q_OS_LINUX64
|
||||
@@ -117,155 +116,3 @@ int32 gAutoDownloadPhoto = 0; // all auto download
|
||||
int32 gAutoDownloadAudio = 0;
|
||||
int32 gAutoDownloadGif = 0;
|
||||
bool gAutoPlayGif = true;
|
||||
|
||||
void ParseCommandLineArguments(const QStringList &arguments) {
|
||||
enum class KeyFormat {
|
||||
NoValues,
|
||||
OneValue,
|
||||
AllLeftValues,
|
||||
};
|
||||
auto parseMap = std::map<QByteArray, KeyFormat> {
|
||||
{ "-testmode" , KeyFormat::NoValues },
|
||||
{ "-debug" , KeyFormat::NoValues },
|
||||
{ "-many" , KeyFormat::NoValues },
|
||||
{ "-key" , KeyFormat::OneValue },
|
||||
{ "-autostart" , KeyFormat::NoValues },
|
||||
{ "-fixprevious", KeyFormat::NoValues },
|
||||
{ "-cleanup" , KeyFormat::NoValues },
|
||||
{ "-noupdate" , KeyFormat::NoValues },
|
||||
{ "-tosettings" , KeyFormat::NoValues },
|
||||
{ "-startintray", KeyFormat::NoValues },
|
||||
{ "-sendpath" , KeyFormat::AllLeftValues },
|
||||
{ "-workdir" , KeyFormat::OneValue },
|
||||
{ "--" , KeyFormat::OneValue },
|
||||
};
|
||||
auto parseResult = QMap<QByteArray, QStringList>();
|
||||
auto parsingKey = QByteArray();
|
||||
auto parsingFormat = KeyFormat::NoValues;
|
||||
for (auto &argument : arguments) {
|
||||
switch (parsingFormat) {
|
||||
case KeyFormat::OneValue: {
|
||||
parseResult[parsingKey] = QStringList(argument.mid(0, 8192));
|
||||
parsingFormat = KeyFormat::NoValues;
|
||||
} break;
|
||||
case KeyFormat::AllLeftValues: {
|
||||
parseResult[parsingKey].push_back(argument.mid(0, 8192));
|
||||
} break;
|
||||
case KeyFormat::NoValues: {
|
||||
parsingKey = argument.toLatin1();
|
||||
auto it = parseMap.find(parsingKey);
|
||||
if (it != parseMap.end()) {
|
||||
parsingFormat = it->second;
|
||||
parseResult[parsingKey] = QStringList();
|
||||
}
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
gTestMode = parseResult.contains("-testmode");
|
||||
gDebug = parseResult.contains("-debug");
|
||||
gManyInstance = parseResult.contains("-many");
|
||||
gKeyFile = parseResult.value("-key", QStringList()).join(QString());
|
||||
gLaunchMode = parseResult.contains("-autostart") ? LaunchModeAutoStart
|
||||
: parseResult.contains("-fixprevious") ? LaunchModeFixPrevious
|
||||
: parseResult.contains("-cleanup") ? LaunchModeCleanup : LaunchModeNormal;
|
||||
gNoStartUpdate = parseResult.contains("-noupdate");
|
||||
gStartToSettings = parseResult.contains("-tosettings");
|
||||
gStartInTray = parseResult.contains("-startintray");
|
||||
gSendPaths = parseResult.value("-sendpath", QStringList());
|
||||
gWorkingDir = parseResult.value("-workdir", QStringList()).join(QString());
|
||||
if (!gWorkingDir.isEmpty() && !QDir().exists(gWorkingDir)) {
|
||||
gWorkingDir = QString();
|
||||
}
|
||||
gStartUrl = parseResult.value("--", QStringList()).join(QString());
|
||||
}
|
||||
|
||||
void InitFromCommandLine(int argc, char *argv[]) {
|
||||
Expects(argc >= 0);
|
||||
|
||||
auto arguments = QStringList();
|
||||
arguments.reserve(argc);
|
||||
for (auto i = 0; i != argc; ++i) {
|
||||
arguments.push_back(fromUtf8Safe(argv[i]));
|
||||
}
|
||||
gArguments = arguments.join(' ');
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
#ifndef OS_MAC_OLD
|
||||
if (QSysInfo::macVersion() >= QSysInfo::MV_10_11) {
|
||||
gIsElCapitan = true;
|
||||
}
|
||||
#else // OS_MAC_OLD
|
||||
if (QSysInfo::macVersion() < QSysInfo::MV_10_7) {
|
||||
gIsSnowLeopard = true;
|
||||
}
|
||||
gPlatform = dbipMacOld;
|
||||
#endif // OS_MAC_OLD
|
||||
#endif // Q_OS_MAC
|
||||
|
||||
switch (cPlatform()) {
|
||||
case dbipWindows:
|
||||
gUpdateURL = QUrl(qsl("http://tdesktop.com/win/tupdates/current"));
|
||||
#ifndef OS_WIN_STORE
|
||||
gPlatformString = qsl("Windows");
|
||||
#else // OS_WIN_STORE
|
||||
gPlatformString = qsl("WinStore");
|
||||
#endif // OS_WIN_STORE
|
||||
break;
|
||||
case dbipMac:
|
||||
gUpdateURL = QUrl(qsl("http://tdesktop.com/mac/tupdates/current"));
|
||||
#ifndef OS_MAC_STORE
|
||||
gPlatformString = qsl("MacOS");
|
||||
#else // OS_MAC_STORE
|
||||
gPlatformString = qsl("MacAppStore");
|
||||
#endif // OS_MAC_STORE
|
||||
break;
|
||||
case dbipMacOld:
|
||||
gUpdateURL = QUrl(qsl("http://tdesktop.com/mac32/tupdates/current"));
|
||||
gPlatformString = qsl("MacOSold");
|
||||
break;
|
||||
case dbipLinux64:
|
||||
gUpdateURL = QUrl(qsl("http://tdesktop.com/linux/tupdates/current"));
|
||||
gPlatformString = qsl("Linux64bit");
|
||||
break;
|
||||
case dbipLinux32:
|
||||
gUpdateURL = QUrl(qsl("http://tdesktop.com/linux32/tupdates/current"));
|
||||
gPlatformString = qsl("Linux32bit");
|
||||
break;
|
||||
}
|
||||
|
||||
auto path = Platform::CurrentExecutablePath(argc, argv);
|
||||
LOG(("Executable path before check: %1").arg(path));
|
||||
if (!path.isEmpty()) {
|
||||
auto info = QFileInfo(path);
|
||||
if (info.isSymLink()) {
|
||||
info = info.symLinkTarget();
|
||||
}
|
||||
if (info.exists()) {
|
||||
gExeDir = info.absoluteDir().absolutePath() + '/';
|
||||
gExeName = info.fileName();
|
||||
}
|
||||
}
|
||||
if (cExeName().isEmpty()) {
|
||||
LOG(("WARNING: Could not compute executable path, some features will be disabled."));
|
||||
}
|
||||
|
||||
ParseCommandLineArguments(arguments);
|
||||
}
|
||||
|
||||
RecentStickerPack &cGetRecentStickers() {
|
||||
if (cRecentStickers().isEmpty() && !cRecentStickersPreload().isEmpty()) {
|
||||
RecentStickerPreload p(cRecentStickersPreload());
|
||||
cSetRecentStickersPreload(RecentStickerPreload());
|
||||
|
||||
RecentStickerPack &recent(cRefRecentStickers());
|
||||
recent.reserve(p.size());
|
||||
for (RecentStickerPreload::const_iterator i = p.cbegin(), e = p.cend(); i != e; ++i) {
|
||||
DocumentData *doc = App::document(i->first);
|
||||
if (!doc || !doc->sticker()) continue;
|
||||
|
||||
recent.push_back(qMakePair(doc, i->second));
|
||||
}
|
||||
}
|
||||
return cRefRecentStickers();
|
||||
}
|
||||
|
||||
@@ -20,8 +20,6 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
void InitFromCommandLine(int argc, char *argv[]);
|
||||
|
||||
extern bool gDebug;
|
||||
inline bool cDebug() {
|
||||
#if defined _DEBUG
|
||||
@@ -55,8 +53,6 @@ inline bool rtl() {
|
||||
return cRtl();
|
||||
}
|
||||
|
||||
DeclareReadSetting(QString, Arguments);
|
||||
|
||||
DeclareSetting(bool, AlphaVersion);
|
||||
DeclareSetting(uint64, BetaVersion);
|
||||
DeclareSetting(uint64, RealBetaVersion);
|
||||
@@ -169,15 +165,13 @@ DeclareRefSetting(EmojiColorVariants, EmojiVariants);
|
||||
|
||||
class DocumentData;
|
||||
|
||||
typedef QList<QPair<DocumentData*, int16> > RecentStickerPackOld;
|
||||
typedef QVector<QPair<uint64, ushort> > RecentStickerPreload;
|
||||
typedef QVector<QPair<DocumentData*, ushort> > RecentStickerPack;
|
||||
typedef QList<QPair<DocumentData*, int16>> RecentStickerPackOld;
|
||||
typedef QVector<QPair<uint64, ushort>> RecentStickerPreload;
|
||||
typedef QVector<QPair<DocumentData*, ushort>> RecentStickerPack;
|
||||
DeclareSetting(RecentStickerPreload, RecentStickersPreload);
|
||||
DeclareRefSetting(RecentStickerPack, RecentStickers);
|
||||
|
||||
RecentStickerPack &cGetRecentStickers();
|
||||
|
||||
typedef QList<QPair<QString, ushort> > RecentHashtagPack;
|
||||
typedef QList<QPair<QString, ushort>> RecentHashtagPack;
|
||||
DeclareRefSetting(RecentHashtagPack, RecentWriteHashtags);
|
||||
DeclareSetting(RecentHashtagPack, RecentSearchHashtags);
|
||||
|
||||
@@ -203,41 +197,6 @@ inline bool passcodeCanTry() {
|
||||
return dt >= 30000;
|
||||
}
|
||||
|
||||
inline void incrementRecentHashtag(RecentHashtagPack &recent, const QString &tag) {
|
||||
RecentHashtagPack::iterator i = recent.begin(), e = recent.end();
|
||||
for (; i != e; ++i) {
|
||||
if (i->first == tag) {
|
||||
++i->second;
|
||||
if (qAbs(i->second) > 0x4000) {
|
||||
for (RecentHashtagPack::iterator j = recent.begin(); j != e; ++j) {
|
||||
if (j->second > 1) {
|
||||
j->second /= 2;
|
||||
} else if (j->second > 0) {
|
||||
j->second = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (; i != recent.begin(); --i) {
|
||||
if (qAbs((i - 1)->second) > qAbs(i->second)) {
|
||||
break;
|
||||
}
|
||||
qSwap(*i, *(i - 1));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == e) {
|
||||
while (recent.size() >= 64) recent.pop_back();
|
||||
recent.push_back(qMakePair(tag, 1));
|
||||
for (i = recent.end() - 1; i != recent.begin(); --i) {
|
||||
if ((i - 1)->second > i->second) {
|
||||
break;
|
||||
}
|
||||
qSwap(*i, *(i - 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DeclareSetting(QStringList, SendPaths);
|
||||
DeclareSetting(QString, StartUrl);
|
||||
|
||||
@@ -271,5 +230,3 @@ DeclareSetting(int32, AutoDownloadPhoto);
|
||||
DeclareSetting(int32, AutoDownloadAudio);
|
||||
DeclareSetting(int32, AutoDownloadGif);
|
||||
DeclareSetting(bool, AutoPlayGif);
|
||||
|
||||
void settingsParseArgs(int argc, char *argv[]);
|
||||
|
||||
@@ -27,6 +27,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||
#include "storage/localstorage.h"
|
||||
#include "platform/platform_file_utilities.h"
|
||||
#include "auth_session.h"
|
||||
#include "core/crash_reports.h"
|
||||
|
||||
namespace Storage {
|
||||
|
||||
@@ -722,11 +723,11 @@ bool mtpFileLoader::feedPart(int offset, base::const_byte_span bytes) {
|
||||
// Debugging weird out of memory crashes.
|
||||
auto info = QString("offset: %1, size: %2, cancelled: %3, finished: %4, filename: '%5', tocache: %6, fromcloud: %7, data: %8, fullsize: %9").arg(offset).arg(bytes.size()).arg(Logs::b(_cancelled)).arg(Logs::b(_finished)).arg(_filename).arg(int(_toCache)).arg(int(_fromCloud)).arg(_data.size()).arg(_size);
|
||||
info += QString(", locationtype: %1, inqueue: %2, localstatus: %3").arg(int(_locationType)).arg(Logs::b(_inQueue)).arg(int(_localStatus));
|
||||
SignalHandlers::setCrashAnnotation("DebugInfo", info);
|
||||
CrashReports::SetAnnotation("DebugInfo", info);
|
||||
}
|
||||
_data.reserve(offset + bytes.size());
|
||||
if (offset > 100 * 1024 * 1024) {
|
||||
SignalHandlers::setCrashAnnotation("DebugInfo", QString());
|
||||
CrashReports::ClearAnnotation("DebugInfo");
|
||||
}
|
||||
|
||||
if (offset > _data.size()) {
|
||||
|
||||
@@ -251,7 +251,7 @@ bool FileLoadTask::CheckForSong(const QString &filepath, const QByteArray &conte
|
||||
if (!CheckMimeOrExtensions(filepath, result->filemime, mimes, extensions)) {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
|
||||
auto media = Media::Player::PrepareForSending(filepath, content);
|
||||
if (media.duration < 0) {
|
||||
return false;
|
||||
|
||||
@@ -22,6 +22,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||
|
||||
#include "storage/serialize_document.h"
|
||||
#include "storage/serialize_common.h"
|
||||
#include "chat_helpers/stickers.h"
|
||||
#include "data/data_drafts.h"
|
||||
#include "window/themes/window_theme.h"
|
||||
#include "observer_peer.h"
|
||||
@@ -1778,7 +1779,7 @@ void _writeUserSettings() {
|
||||
}
|
||||
|
||||
size += sizeof(quint32) + sizeof(qint32) + cEmojiVariants().size() * (sizeof(uint32) + sizeof(uint64));
|
||||
size += sizeof(quint32) + sizeof(qint32) + (cRecentStickersPreload().isEmpty() ? cGetRecentStickers().size() : cRecentStickersPreload().size()) * (sizeof(uint64) + sizeof(ushort));
|
||||
size += sizeof(quint32) + sizeof(qint32) + (Stickers::GetRecentPack().isEmpty() ? Stickers::GetRecentPack().size() : cRecentStickersPreload().size()) * (sizeof(uint64) + sizeof(ushort));
|
||||
size += sizeof(quint32) + Serialize::stringSize(cDialogLastPath());
|
||||
size += sizeof(quint32) + 3 * sizeof(qint32);
|
||||
size += sizeof(quint32) + 2 * sizeof(qint32);
|
||||
@@ -1822,11 +1823,11 @@ void _writeUserSettings() {
|
||||
}
|
||||
data.stream << quint32(dbiEmojiVariants) << cEmojiVariants();
|
||||
{
|
||||
RecentStickerPreload v(cRecentStickersPreload());
|
||||
auto v = cRecentStickersPreload();
|
||||
if (v.isEmpty()) {
|
||||
v.reserve(cGetRecentStickers().size());
|
||||
for (RecentStickerPack::const_iterator i = cGetRecentStickers().cbegin(), e = cGetRecentStickers().cend(); i != e; ++i) {
|
||||
v.push_back(qMakePair(i->first->id, i->second));
|
||||
v.reserve(Stickers::GetRecentPack().size());
|
||||
for_const (auto &pair, Stickers::GetRecentPack()) {
|
||||
v.push_back(qMakePair(pair.first->id, pair.second));
|
||||
}
|
||||
}
|
||||
data.stream << quint32(dbiRecentStickers) << v;
|
||||
|
||||
@@ -20,6 +20,8 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||
*/
|
||||
#include "ui/text/text_block.h"
|
||||
|
||||
#include "core/crash_reports.h"
|
||||
|
||||
// COPIED FROM qtextlayout.cpp AND MODIFIED
|
||||
namespace {
|
||||
|
||||
@@ -327,7 +329,7 @@ TextBlock::TextBlock(const style::font &font, const QString &str, QFixed minResi
|
||||
QString part = str.mid(_from, length);
|
||||
|
||||
// Attempt to catch a crash in text processing
|
||||
SignalHandlers::setCrashAnnotationRef("CrashString", &part);
|
||||
CrashReports::SetAnnotationRef("CrashString", &part);
|
||||
|
||||
QStackTextEngine engine(part, blockFont->f);
|
||||
QTextLayout layout(&engine);
|
||||
@@ -338,7 +340,7 @@ TextBlock::TextBlock(const style::font &font, const QString &str, QFixed minResi
|
||||
|
||||
layout.endLayout();
|
||||
|
||||
SignalHandlers::clearCrashAnnotationRef("CrashString");
|
||||
CrashReports::ClearAnnotationRef("CrashString");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -130,7 +130,7 @@ Controller::ColumnLayout Controller::computeColumnLayout() const {
|
||||
int Controller::countDialogsWidthFromRatio(int bodyWidth) const {
|
||||
auto result = qRound(bodyWidth * Auth().data().dialogsWidthRatio());
|
||||
accumulate_max(result, st::columnMinimalWidthLeft);
|
||||
accumulate_min(result, st::columnMaximalWidthLeft);
|
||||
// accumulate_min(result, st::columnMaximalWidthLeft);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -398,3 +398,8 @@ if [ "$BuildTarget" == "mac" ] || [ "$BuildTarget" == "mac32" ] || [ "$BuildTarg
|
||||
fi
|
||||
|
||||
echo "Version $AppVersionStrFull is ready!";
|
||||
echo -en "\007";
|
||||
sleep 1;
|
||||
echo -en "\007";
|
||||
sleep 1;
|
||||
echo -en "\007";
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
AppVersion 1002000
|
||||
AppVersion 1002001
|
||||
AppVersionStrMajor 1.2
|
||||
AppVersionStrSmall 1.2
|
||||
AppVersionStr 1.2.0
|
||||
AppVersionStrSmall 1.2.1
|
||||
AppVersionStr 1.2.1
|
||||
AlphaChannel 0
|
||||
BetaVersion 0
|
||||
|
||||
@@ -28,7 +28,7 @@ else
|
||||
#gyp --depth=. --generator-output=../.. -Goutput_dir=out Telegram.gyp --format=xcode-ninja
|
||||
#gyp --depth=. --generator-output=../.. -Goutput_dir=out Telegram.gyp --format=xcode
|
||||
# use patched gyp with Xcode project generator
|
||||
../../../Libraries/gyp/gyp --depth=. --generator-output=.. -Goutput_dir=../out -Gxcode_upgrade_check_project_version=910 -Dofficial_build_target=$BuildTarget Telegram.gyp --format=xcode
|
||||
../../../Libraries/gyp/gyp --depth=. --generator-output=.. -Goutput_dir=../out -Gxcode_upgrade_check_project_version=920 -Dofficial_build_target=$BuildTarget Telegram.gyp --format=xcode
|
||||
fi
|
||||
|
||||
cd ../..
|
||||
|
||||
@@ -35,12 +35,12 @@
|
||||
'VCCLCompilerTool': {
|
||||
'ProgramDataBaseFileName': '$(OutDir)\\$(ProjectName).pdb',
|
||||
'DebugInformationFormat': '3', # Program Database (/Zi)
|
||||
'WarnAsError': 'true',
|
||||
'AdditionalOptions': [
|
||||
'/std:c++latest',
|
||||
'/permissive-',
|
||||
'/permissive-',
|
||||
'/MP', # Enable multi process build.
|
||||
'/EHsc', # Catch C++ exceptions only, extern C functions never throw a C++ exception.
|
||||
'/WX', # Treat warnings as errors.
|
||||
'/w14834', # [[nodiscard]]
|
||||
],
|
||||
'TreatWChar_tAsBuiltInType': 'false',
|
||||
|
||||
@@ -141,8 +141,14 @@
|
||||
<(src_loc)/core/click_handler.h
|
||||
<(src_loc)/core/click_handler_types.cpp
|
||||
<(src_loc)/core/click_handler_types.h
|
||||
<(src_loc)/core/crash_report_window.cpp
|
||||
<(src_loc)/core/crash_report_window.h
|
||||
<(src_loc)/core/crash_reports.cpp
|
||||
<(src_loc)/core/crash_reports.h
|
||||
<(src_loc)/core/file_utilities.cpp
|
||||
<(src_loc)/core/file_utilities.h
|
||||
<(src_loc)/core/launcher.cpp
|
||||
<(src_loc)/core/launcher.h
|
||||
<(src_loc)/core/single_timer.cpp
|
||||
<(src_loc)/core/single_timer.h
|
||||
<(src_loc)/core/tl_help.h
|
||||
@@ -398,6 +404,8 @@
|
||||
<(src_loc)/platform/linux/linux_libs.h
|
||||
<(src_loc)/platform/linux/file_utilities_linux.cpp
|
||||
<(src_loc)/platform/linux/file_utilities_linux.h
|
||||
<(src_loc)/platform/linux/launcher_linux.cpp
|
||||
<(src_loc)/platform/linux/launcher_linux.h
|
||||
<(src_loc)/platform/linux/main_window_linux.cpp
|
||||
<(src_loc)/platform/linux/main_window_linux.h
|
||||
<(src_loc)/platform/linux/notifications_manager_linux.cpp
|
||||
@@ -406,6 +414,8 @@
|
||||
<(src_loc)/platform/linux/specific_linux.h
|
||||
<(src_loc)/platform/mac/file_utilities_mac.mm
|
||||
<(src_loc)/platform/mac/file_utilities_mac.h
|
||||
<(src_loc)/platform/mac/launcher_mac.mm
|
||||
<(src_loc)/platform/mac/launcher_mac.h
|
||||
<(src_loc)/platform/mac/mac_iconv_helper.c
|
||||
<(src_loc)/platform/mac/mac_utilities.mm
|
||||
<(src_loc)/platform/mac/mac_utilities.h
|
||||
@@ -423,6 +433,8 @@
|
||||
<(src_loc)/platform/win/audio_win.h
|
||||
<(src_loc)/platform/win/file_utilities_win.cpp
|
||||
<(src_loc)/platform/win/file_utilities_win.h
|
||||
<(src_loc)/platform/win/launcher_win.cpp
|
||||
<(src_loc)/platform/win/launcher_win.h
|
||||
<(src_loc)/platform/win/main_window_win.cpp
|
||||
<(src_loc)/platform/win/main_window_win.h
|
||||
<(src_loc)/platform/win/notifications_manager_win.cpp
|
||||
@@ -440,6 +452,7 @@
|
||||
<(src_loc)/platform/win/windows_range_v3_helpers.h
|
||||
<(src_loc)/platform/platform_audio.h
|
||||
<(src_loc)/platform/platform_file_utilities.h
|
||||
<(src_loc)/platform/platform_launcher.h
|
||||
<(src_loc)/platform/platform_main_window.h
|
||||
<(src_loc)/platform/platform_notifications_manager.h
|
||||
<(src_loc)/platform/platform_specific.h
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
1.2.1 (12.12.17)
|
||||
|
||||
- Bug fixes and other minor improvements.
|
||||
|
||||
1.2.0 (10.12.17)
|
||||
|
||||
- Radically improved navigation. New side panel on the right with quick access to shared media and group members.
|
||||
|
||||
Reference in New Issue
Block a user