Merge branch 'dev' of https://github.com/telegramdesktop/tdesktop into telegramdesktop-dev2

This commit is contained in:
ZavaruKitsu 2023-07-18 11:19:23 +00:00
commit eb9b35461b
45 changed files with 489 additions and 403 deletions

View file

@ -25,7 +25,12 @@ jobs:
submodules: recursive
- name: First set up.
run: curl -sSL https://install.python-poetry.org | python3 -
run: |
sudo apt update
curl -sSL https://install.python-poetry.org | python3 -
- name: Free up some disk space.
uses: jlumbroso/free-disk-space@76866dbe54312617f00798d1762df7f43def6e5c
- name: Docker image build.
run: |

View file

@ -60,6 +60,9 @@ jobs:
sudo snap run lxd init --auto
sudo snap run lxd waitready
- name: Free up some disk space.
uses: jlumbroso/free-disk-space@76866dbe54312617f00798d1762df7f43def6e5c
- name: Telegram Desktop snap build.
run: sg lxd -c 'snap run snapcraft -v'

View file

@ -1774,5 +1774,6 @@ if (LINUX AND DESKTOP_APP_USE_PACKAGED)
install(FILES "Resources/art/icon256.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/256x256/apps" RENAME "telegram.png")
install(FILES "Resources/art/icon512.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/512x512/apps" RENAME "telegram.png")
install(FILES "../lib/xdg/org.ayugram.desktop.desktop" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/applications")
install(FILES "../lib/xdg/org.telegram.desktop.service" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/dbus-1/services")
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/org.ayugram.desktop.metainfo.xml" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/metainfo")
endif()

View file

@ -10,7 +10,7 @@
<Identity Name="TelegramMessengerLLP.TelegramDesktop"
ProcessorArchitecture="ARCHITECTURE"
Publisher="CN=536BC709-8EE1-4478-AF22-F0F0F26FF64A"
Version="4.8.3.0" />
Version="4.8.4.0" />
<Properties>
<DisplayName>Telegram Desktop</DisplayName>
<PublisherDisplayName>Telegram Messenger LLP</PublisherDisplayName>

View file

@ -44,8 +44,8 @@ IDI_ICON1 ICON "..\\art\\icon256.ico"
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 4,8,3,0
PRODUCTVERSION 4,8,3,0
FILEVERSION 4,8,4,0
PRODUCTVERSION 4,8,4,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@ -62,10 +62,10 @@ BEGIN
BEGIN
VALUE "CompanyName", "Radolyn Labs"
VALUE "FileDescription", "AyuGram Desktop"
VALUE "FileVersion", "4.8.3.0"
VALUE "FileVersion", "4.8.4.0"
VALUE "LegalCopyright", "Copyright (C) 2014-2023"
VALUE "ProductName", "AyuGram Desktop"
VALUE "ProductVersion", "4.8.3.0"
VALUE "ProductVersion", "4.8.4.0"
END
END
BLOCK "VarFileInfo"

View file

@ -35,8 +35,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 4,8,3,0
PRODUCTVERSION 4,8,3,0
FILEVERSION 4,8,4,0
PRODUCTVERSION 4,8,4,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@ -53,10 +53,10 @@ BEGIN
BEGIN
VALUE "CompanyName", "Radolyn Labs"
VALUE "FileDescription", "AyuGram Desktop Updater"
VALUE "FileVersion", "4.8.3.0"
VALUE "FileVersion", "4.8.4.0"
VALUE "LegalCopyright", "Copyright (C) 2014-2023"
VALUE "ProductName", "AyuGram Desktop"
VALUE "ProductVersion", "4.8.3.0"
VALUE "ProductVersion", "4.8.4.0"
END
END
BLOCK "VarFileInfo"

View file

@ -7,12 +7,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "packer.h"
#include <QtCore/QtPlugin>
#ifdef Q_OS_MAC
//Q_IMPORT_PLUGIN(QCocoaIntegrationPlugin)
#endif
bool BetaChannel = false;
quint64 AlphaVersion = 0;
bool OnlyAlphaKey = false;

View file

@ -46,6 +46,7 @@ string updaterName;
string workDir;
string exeName;
string exePath;
string argv0;
FILE *_logFile = 0;
void openLog() {
@ -388,6 +389,8 @@ int main(int argc, char *argv[]) {
exeName = argv[i];
} else if (equal(argv[i], "-exepath") && ++i < argc) {
exePath = argv[i];
} else if (equal(argv[i], "-argv0") && ++i < argc) {
argv0 = argv[i];
}
}
if (exeName.empty() || exeName.find('/') != string::npos) {
@ -461,15 +464,14 @@ int main(int argc, char *argv[]) {
writeLog("Error: short exe name!");
}
auto fullBinaryPath = exePath + exeName;
const auto path = fullBinaryPath.c_str();
const auto fullBinaryPath = exePath + exeName;
auto values = vector<string>();
const auto push = [&](string arg) {
// Force null-terminated .data() call result.
values.push_back(arg + char(0));
};
push(path);
push(!argv0.empty() ? argv0 : fullBinaryPath);
push("-noupdate");
if (autostart) push("-autostart");
if (debug) push("-debug");
@ -498,7 +500,7 @@ int main(int argc, char *argv[]) {
writeLog("fork() failed!");
return 1;
case 0:
execv(args[0], args.data());
execv(fullBinaryPath.c_str(), args.data());
return 1;
}
}

View file

@ -143,9 +143,8 @@ struct Application::Private {
Settings settings;
};
Application::Application(not_null<Launcher*> launcher)
Application::Application()
: QObject()
, _launcher(launcher)
, _private(std::make_unique<Private>())
, _platformIntegration(Platform::Integration::Create())
, _batterySaving(std::make_unique<base::BatterySaving>())
@ -945,11 +944,11 @@ rpl::producer<> Application::materializeLocalDraftsRequests() const {
void Application::switchDebugMode() {
if (Logs::DebugEnabled()) {
Logs::SetDebugEnabled(false);
_launcher->writeDebugModeSetting();
Launcher::Instance().writeDebugModeSetting();
Restart();
} else {
Logs::SetDebugEnabled(true);
_launcher->writeDebugModeSetting();
Launcher::Instance().writeDebugModeSetting();
DEBUG_LOG(("Debug logs started."));
if (_lastActivePrimaryWindow) {
_lastActivePrimaryWindow->hideLayer();
@ -957,10 +956,6 @@ void Application::switchDebugMode() {
}
}
void Application::writeInstallBetaVersionsSetting() {
_launcher->writeInstallBetaVersionsSetting();
}
Main::Account &Application::activeAccount() const {
return _domain->active();
}
@ -1767,10 +1762,8 @@ void Application::startShortcuts() {
void Application::RegisterUrlScheme() {
base::Platform::RegisterUrlScheme(base::Platform::UrlSchemeDescriptor{
.executable = (!Platform::IsLinux() || !Core::UpdaterDisabled())
? (cExeDir() + cExeName())
: cExeName(),
.arguments = Sandbox::Instance().customWorkingDir()
.executable = Platform::ExecutablePathForShortcuts(),
.arguments = Launcher::Instance().customWorkingDir()
? u"-workdir \"%1\""_q.arg(cWorkingDir())
: QString(),
.protocol = u"tg"_q,

View file

@ -103,7 +103,6 @@ class Instance;
namespace Core {
class Launcher;
struct LocalUrlHandler;
class Settings;
class Tray;
@ -126,16 +125,13 @@ public:
MTP::ProxyData now;
};
Application(not_null<Launcher*> launcher);
Application();
Application(const Application &other) = delete;
Application &operator=(const Application &other) = delete;
~Application();
void run();
[[nodiscard]] Launcher &launcher() const {
return *_launcher;
}
[[nodiscard]] Platform::Integration &platformIntegration() const {
return *_platformIntegration;
}
@ -319,7 +315,6 @@ public:
[[nodiscard]] rpl::producer<> materializeLocalDraftsRequests() const;
void switchDebugMode();
void writeInstallBetaVersionsSetting();
void preventOrInvoke(Fn<void()> &&callback);
@ -381,7 +376,6 @@ private:
};
InstanceSetter _setter = { this };
const not_null<Launcher*> _launcher;
rpl::event_stream<ProxyChange> _proxyChanges;
// Some fields are just moved from the declaration.

View file

@ -9,7 +9,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "core/crash_reports.h"
#include "core/application.h"
#include "core/launcher.h"
#include "core/sandbox.h"
#include "core/update_checker.h"
#include "core/ui_integration.h"
@ -250,7 +249,6 @@ LastCrashedWindow::UpdaterData::UpdaterData(QWidget *buttonParent)
}
LastCrashedWindow::LastCrashedWindow(
not_null<Core::Launcher*> launcher,
const QByteArray &crashdump,
Fn<void()> launch)
: _dumpraw(crashdump)

View file

@ -20,10 +20,6 @@ namespace MTP {
struct ProxyData;
} // namespace MTP
namespace Core {
class Launcher;
} // namespace Core
class PreLaunchWindow : public QWidget {
public:
PreLaunchWindow(QString title = QString());
@ -94,10 +90,7 @@ private:
class LastCrashedWindow : public PreLaunchWindow {
public:
LastCrashedWindow(
not_null<Core::Launcher*> launcher,
const QByteArray &crashdump,
Fn<void()> launch);
LastCrashedWindow(const QByteArray &crashdump, Fn<void()> launch);
rpl::producer<MTP::ProxyData> proxyChanges() const;

View file

@ -313,7 +313,7 @@ QString PlatformString() {
Unexpected("Platform in CrashReports::PlatformString.");
}
void StartCatching(not_null<Core::Launcher*> launcher) {
void StartCatching() {
#ifndef DESKTOP_APP_DISABLE_CRASH_REPORTS
ProcessAnnotations["Binary"] = cExeName().toUtf8().constData();
ProcessAnnotations["ApiId"] = QString::number(ApiId).toUtf8().constData();
@ -324,7 +324,7 @@ void StartCatching(not_null<Core::Launcher*> launcher) {
: u"%1"_q).arg(AppVersion)).toUtf8().constData();
ProcessAnnotations["Launched"] = QDateTime::currentDateTime().toString("dd.MM.yyyy hh:mm:ss").toUtf8().constData();
ProcessAnnotations["Platform"] = PlatformString().toUtf8().constData();
ProcessAnnotations["UserTag"] = QString::number(launcher->installationTag(), 16).toUtf8().constData();
ProcessAnnotations["UserTag"] = QString::number(Core::Launcher::Instance().installationTag(), 16).toUtf8().constData();
QString dumpspath = cWorkingDir() + u"tdata/dumps"_q;
QDir().mkpath(dumpspath);

View file

@ -7,10 +7,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
namespace Core {
class Launcher;
} // namespace Core
namespace CrashReports {
QString PlatformString();
@ -53,7 +49,7 @@ inline void ClearAnnotationRef(const std::string &key) {
SetAnnotationRef(key, nullptr);
}
void StartCatching(not_null<Core::Launcher*> launcher);
void StartCatching();
void FinishCatching();
} // namespace CrashReports

View file

@ -281,6 +281,8 @@ base::options::toggle OptionFractionalScalingEnabled({
const char kOptionFractionalScalingEnabled[] = "fractional-scaling-enabled";
const char kOptionFreeType[] = "freetype";
Launcher *Launcher::InstanceSetter::Instance = nullptr;
std::unique_ptr<Launcher> Launcher::Create(int argc, char *argv[]) {
return std::make_unique<Platform::Launcher>(argc, argv);
}
@ -288,15 +290,18 @@ std::unique_ptr<Launcher> Launcher::Create(int argc, char *argv[]) {
Launcher::Launcher(int argc, char *argv[])
: _argc(argc)
, _argv(argv)
, _arguments(readArguments(_argc, _argv))
, _baseIntegration(_argc, _argv) {
crl::toggle_fp_exceptions(true);
base::Integration::Set(&_baseIntegration);
}
void Launcher::init() {
_arguments = readArguments(_argc, _argv);
Launcher::~Launcher() {
InstanceSetter::Instance = nullptr;
}
void Launcher::init() {
prepareSettings();
initQtMessageLogging();
@ -343,7 +348,7 @@ int Launcher::exec() {
}
// Must be started before Platform is started.
Logs::start(this);
Logs::start();
base::options::init(cWorkingDir() + "tdata/experimental_options.json");
// Must be called after options are inited.
@ -425,8 +430,8 @@ QStringList Launcher::readArguments(int argc, char *argv[]) const {
return result;
}
QString Launcher::argumentsString() const {
return _arguments.join(' ');
const QStringList &Launcher::arguments() const {
return _arguments;
}
bool Launcher::customWorkingDir() const {
@ -436,17 +441,6 @@ bool Launcher::customWorkingDir() const {
void Launcher::prepareSettings() {
auto path = base::Platform::CurrentExecutablePath(_argc, _argv);
LOG(("Executable path before check: %1").arg(path));
if (!path.isEmpty()) {
auto info = QFileInfo(path);
if (info.isSymLink()) {
info = QFileInfo(info.symLinkTarget());
}
if (info.exists()) {
const auto dir = info.absoluteDir().absolutePath();
gExeDir = (dir.endsWith('/') ? dir : (dir + '/'));
gExeName = info.fileName();
}
}
if (cExeName().isEmpty()) {
LOG(("WARNING: Could not compute executable path, some features will be disabled."));
}
@ -558,7 +552,7 @@ void Launcher::processArguments() {
int Launcher::executeApplication() {
FilteredCommandLineArguments arguments(_argc, _argv);
Sandbox sandbox(this, arguments.count(), arguments.values());
Sandbox sandbox(arguments.count(), arguments.values());
Ui::MainQueueProcessor processor;
base::ConcurrentTimerEnvironment environment;
return sandbox.start();

View file

@ -20,9 +20,15 @@ public:
static std::unique_ptr<Launcher> Create(int argc, char *argv[]);
static Launcher &Instance() {
Expects(InstanceSetter::Instance != nullptr);
return *InstanceSetter::Instance;
}
virtual int exec();
QString argumentsString() const;
const QStringList &arguments() const;
bool customWorkingDir() const;
uint64 installationTag() const;
@ -32,7 +38,7 @@ public:
void writeDebugModeSetting();
void writeInstallBetaVersionsSetting();
virtual ~Launcher() = default;
virtual ~Launcher();
protected:
enum class UpdaterLaunch {
@ -61,6 +67,17 @@ private:
int executeApplication();
struct InstanceSetter {
InstanceSetter(not_null<Launcher*> instance) {
Expects(Instance == nullptr);
Instance = instance;
}
static Launcher *Instance;
};
InstanceSetter _setter = { this };
int _argc;
char **_argv;
QStringList _arguments;

View file

@ -80,13 +80,9 @@ QString _escapeFrom7bit(const QString &str) {
bool Sandbox::QuitOnStartRequested = false;
Sandbox::Sandbox(
not_null<Core::Launcher*> launcher,
int &argc,
char **argv)
Sandbox::Sandbox(int &argc, char **argv)
: QApplication(argc, argv)
, _mainThreadId(QThread::currentThreadId())
, _launcher(launcher) {
, _mainThreadId(QThread::currentThreadId()) {
setQuitOnLastWindowClosed(false);
}
@ -109,7 +105,8 @@ int Sandbox::start() {
hashMd5Hex(d.constData(), d.size(), h.data());
_lockFile = std::make_unique<QLockFile>(QDir::tempPath() + '/' + h + '-' + cGUIDStr());
_lockFile->setStaleLockTime(0);
if (!_lockFile->tryLock() && _launcher->customWorkingDir()) {
if (!_lockFile->tryLock()
&& Launcher::Instance().customWorkingDir()) {
// On Windows, QLockFile has problems detecting a stale lock
// if the machine's hostname contains characters outside the US-ASCII character set.
if constexpr (Platform::IsWindows()) {
@ -204,7 +201,7 @@ void Sandbox::launchApplication() {
}
setupScreenScale();
_application = std::make_unique<Application>(_launcher);
_application = std::make_unique<Application>();
// Ideally this should go to constructor.
// But we want to catch all native events and Application installs
@ -405,7 +402,6 @@ void Sandbox::singleInstanceChecked() {
}
_lastCrashDump = crashdump;
auto window = new LastCrashedWindow(
_launcher,
_lastCrashDump,
[=] { launchApplication(); });
window->proxyChanges(
@ -533,14 +529,6 @@ void Sandbox::refreshGlobalProxy() {
}
}
bool Sandbox::customWorkingDir() const {
return _launcher->customWorkingDir();
}
uint64 Sandbox::installationTag() const {
return _launcher->installationTag();
}
void Sandbox::checkForEmptyLoopNestingLevel() {
// _loopNestingLevel == _eventNestingLevel means that we had a
// native event in a nesting loop that didn't get a notify() call

View file

@ -19,7 +19,6 @@ class QLockFile;
namespace Core {
class Launcher;
class UpdateChecker;
class Application;
@ -33,7 +32,7 @@ private:
}
public:
Sandbox(not_null<Launcher*> launcher, int &argc, char **argv);
Sandbox(int &argc, char **argv);
Sandbox(const Sandbox &other) = delete;
Sandbox &operator=(const Sandbox &other) = delete;
@ -41,8 +40,6 @@ public:
int start();
void refreshGlobalProxy();
bool customWorkingDir() const;
uint64 installationTag() const;
void postponeCall(FnMut<void()> &&callable);
bool notify(QObject *receiver, QEvent *e) override;
@ -116,7 +113,6 @@ private:
std::vector<int> _previousLoopNestingLevels;
std::vector<PostponedCall> _postponedCalls;
not_null<Launcher*> _launcher;
std::unique_ptr<Application> _application;
QString _localServerName, _localSocketReadData;

View file

@ -22,7 +22,7 @@ constexpr auto AppId = "{53F49750-6209-4FBF-9CA8-7A333C87D666}"_cs;
constexpr auto AppNameOld = "AyuGram for Windows"_cs;
constexpr auto AppName = "AyuGram Desktop"_cs;
constexpr auto AppFile = "AyuGram"_cs;
constexpr auto AppVersion = 4008003;
constexpr auto AppVersionStr = "4.8.3";
constexpr auto AppVersion = 4008004;
constexpr auto AppVersionStr = "4.8.4";
constexpr auto AppBetaVersion = false;
constexpr auto AppAlphaVersion = TDESKTOP_ALPHA_VERSION;

View file

@ -343,10 +343,10 @@ bool WritingEntry() {
return WritingEntryFlag;
}
void start(not_null<Core::Launcher*> launcher) {
void start() {
Assert(LogsData == nullptr);
if (!launcher->checkPortableVersionFolder()) {
if (!Core::Launcher::Instance().checkPortableVersionFolder()) {
return;
}
@ -414,8 +414,8 @@ void start(not_null<Core::Launcher*> launcher) {
QDir().mkpath(cWorkingDir() + u"tdata"_q);
launcher->workingFolderReady();
CrashReports::StartCatching(launcher);
Core::Launcher::Instance().workingFolderReady();
CrashReports::StartCatching();
if (!LogsData->openMain()) {
delete LogsData;
@ -430,7 +430,7 @@ void start(not_null<Core::Launcher*> launcher) {
LOG(("Executable dir: %1, name: %2").arg(cExeDir(), cExeName()));
LOG(("Initial working dir: %1").arg(initialWorkingDir));
LOG(("Working dir: %1").arg(cWorkingDir()));
LOG(("Command line: %1").arg(launcher->argumentsString()));
LOG(("Command line: %1").arg(Core::Launcher::Instance().arguments().join(' ')));
if (!LogsData) {
LOG(("FATAL: Could not open '%1' for writing log!"

View file

@ -11,17 +11,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "base/assertion.h"
#include "base/debug_log.h"
namespace Core {
class Launcher;
} // namespace Core
namespace Logs {
void SetDebugEnabled(bool enabled);
bool DebugEnabled();
[[nodiscard]] bool WritingEntry();
void start(not_null<Core::Launcher*> launcher);
void start();
bool started();
void finish();

View file

@ -65,7 +65,7 @@ QByteArray DnsUserAgent() {
static const auto kResult = QByteArray(
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/113.0.5672.63 Safari/537.36");
"Chrome/114.0.5735.133 Safari/537.36");
return kResult;
}

View file

@ -8,20 +8,89 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "platform/linux/integration_linux.h"
#include "platform/platform_integration.h"
#include "base/platform/base_platform_info.h"
#include "base/platform/linux/base_linux_glibmm_helper.h"
#include "base/platform/linux/base_linux_xdp_utilities.h"
#include "core/sandbox.h"
#include "core/application.h"
#include "core/core_settings.h"
#include "base/random.h"
#include <xdpinhibit/xdpinhibit.hpp>
#include <glibmm.h>
#include <QtCore/QAbstractEventDispatcher>
using namespace gi::repository;
#include <xdpinhibit/xdpinhibit.hpp>
#include <giomm.h>
typedef GApplication TDesktopApplication;
typedef GApplicationClass TDesktopApplicationClass;
G_DEFINE_TYPE(
TDesktopApplication,
t_desktop_application,
G_TYPE_APPLICATION)
static void t_desktop_application_class_init(
TDesktopApplicationClass *klass) {
const auto application_class = G_APPLICATION_CLASS(klass);
application_class->local_command_line = [](
GApplication *application,
char ***arguments,
int *exit_status) -> gboolean {
return false;
};
application_class->command_line = [](
GApplication *application,
GApplicationCommandLine *cmdline) {
return 0;
};
application_class->before_emit = [](
GApplication *application,
GVariant *platformData) {
if (Platform::IsWayland()) {
static const auto keys = {
"activation-token",
"desktop-startup-id",
};
for (const auto &key : keys) {
const char *token = nullptr;
g_variant_lookup(platformData, key, "&s", &token);
if (token) {
qputenv("XDG_ACTIVATION_TOKEN", token);
break;
}
}
}
};
application_class->add_platform_data = [](
GApplication *application,
GVariantBuilder *builder) {
if (Platform::IsWayland()) {
const auto token = qgetenv("XDG_ACTIVATION_TOKEN");
if (!token.isEmpty()) {
g_variant_builder_add(
builder,
"{sv}",
"activation-token",
g_variant_new_string(token.constData()));
qunsetenv("XDG_ACTIVATION_TOKEN");
}
}
};
}
static void t_desktop_application_init(TDesktopApplication *application) {
}
namespace Platform {
namespace {
using namespace gi::repository;
namespace Gio = gi::repository::Gio;
class LinuxIntegration final : public Integration {
public:
LinuxIntegration();
@ -33,6 +102,10 @@ private:
return _inhibitProxy;
}
void initInhibit();
static void LaunchNativeApplication();
XdpInhibit::InhibitProxy _inhibitProxy;
base::Platform::XDP::SettingWatcher _darkModeWatcher;
};
@ -61,9 +134,25 @@ LinuxIntegration::LinuxIntegration()
}
}
}) {
LOG(("Icon theme: %1").arg(QIcon::themeName()));
LOG(("Fallback icon theme: %1").arg(QIcon::fallbackThemeName()));
if (!QCoreApplication::eventDispatcher()->inherits(
"QEventDispatcherGlib")) {
g_warning("Qt is running without GLib event loop integration, "
"except various functionality to not to work.");
}
}
void LinuxIntegration::init() {
initInhibit();
Glib::signal_idle().connect_once([] {
LaunchNativeApplication();
});
}
void LinuxIntegration::initInhibit() {
if (!_inhibitProxy) {
return;
}
@ -119,6 +208,111 @@ void LinuxIntegration::init() {
nullptr);
}
void LinuxIntegration::LaunchNativeApplication() {
const auto appId = QGuiApplication::desktopFileName()
.chopped(8)
.toStdString();
const auto app = Glib::wrap(
G_APPLICATION(
g_object_new(
t_desktop_application_get_type(),
"application-id",
::Gio::Application::id_is_valid(appId)
? appId.c_str()
: nullptr,
"flags",
G_APPLICATION_HANDLES_OPEN,
nullptr)));
app->signal_startup().connect([=] {
// GNotification
InvokeQueued(qApp, [] {
Core::App().notifications().createManager();
});
QEventLoop().exec();
app->quit();
}, true);
app->signal_activate().connect([] {
Core::Sandbox::Instance().customEnterFromEventLoop([] {
Core::App().activate();
});
}, true);
app->signal_open().connect([](
const ::Gio::Application::type_vec_files &files,
const Glib::ustring &hint) {
Core::Sandbox::Instance().customEnterFromEventLoop([&] {
for (const auto &file : files) {
QFileOpenEvent e(
QUrl(QString::fromStdString(file->get_uri())));
QGuiApplication::sendEvent(qApp, &e);
}
});
}, true);
app->add_action("quit", [] {
Core::Sandbox::Instance().customEnterFromEventLoop([] {
Core::Quit();
});
});
using Window::Notifications::Manager;
using NotificationId = Manager::NotificationId;
using NotificationIdTuple = std::invoke_result_t<
decltype(&NotificationId::toTuple),
NotificationId*
>;
const auto notificationIdVariantType = [] {
try {
return base::Platform::MakeGlibVariant(
NotificationId().toTuple()).get_type();
} catch (...) {
return Glib::VariantType();
}
}();
app->add_action_with_parameter(
"notification-activate",
notificationIdVariantType,
[](const Glib::VariantBase &parameter) {
Core::Sandbox::Instance().customEnterFromEventLoop([&] {
try {
const auto &app = Core::App();
app.notifications().manager().notificationActivated(
NotificationId::FromTuple(
base::Platform::GlibVariantCast<
NotificationIdTuple
>(parameter)));
} catch (...) {
}
});
});
app->add_action_with_parameter(
"notification-mark-as-read",
notificationIdVariantType,
[](const Glib::VariantBase &parameter) {
Core::Sandbox::Instance().customEnterFromEventLoop([&] {
try {
const auto &app = Core::App();
app.notifications().manager().notificationReplied(
NotificationId::FromTuple(
base::Platform::GlibVariantCast<
NotificationIdTuple
>(parameter)),
{});
} catch (...) {
}
});
});
app->run(0, nullptr);
}
} // namespace
std::unique_ptr<Integration> CreateIntegration() {

View file

@ -24,8 +24,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace Platform {
namespace {
Launcher *LauncherInstance = nullptr;
class Arguments {
public:
void push(QByteArray argument) {
@ -48,23 +46,13 @@ private:
} // namespace
Launcher::Launcher(int argc, char *argv[])
: Core::Launcher(argc, argv)
, _arguments(argv, argv + argc) {
Expects(LauncherInstance == nullptr);
LauncherInstance = this;
}
Launcher &Launcher::Instance() {
Expects(LauncherInstance != nullptr);
return *LauncherInstance;
: Core::Launcher(argc, argv) {
}
int Launcher::exec() {
for (auto i = begin(_arguments), e = end(_arguments); i != e; ++i) {
if (*i == "-webviewhelper" && std::distance(i, e) > 1) {
Webview::WebKitGTK::SetSocketPath(*(i + 1));
for (auto i = arguments().begin(), e = arguments().end(); i != e; ++i) {
if (*i == u"-webviewhelper"_q && std::distance(i, e) > 1) {
Webview::WebKitGTK::SetSocketPath((i + 1)->toStdString());
return Webview::WebKitGTK::Exec();
}
}
@ -81,17 +69,23 @@ bool Launcher::launchUpdater(UpdaterLaunch action) {
return false;
}
const auto binaryPath = (action == UpdaterLaunch::JustRelaunch)
? (cExeDir() + cExeName())
: (cWriteProtected()
const auto justRelaunch = action == UpdaterLaunch::JustRelaunch;
const auto writeProtectedUpdate = action == UpdaterLaunch::PerformUpdate
&& cWriteProtected();
const auto binaryPath = justRelaunch
? QFile::encodeName(cExeDir() + cExeName())
: QFile::encodeName(cWriteProtected()
? (cWorkingDir() + u"tupdates/temp/Updater"_q)
: (cExeDir() + u"Updater"_q));
auto argumentsList = Arguments();
if (action == UpdaterLaunch::PerformUpdate && cWriteProtected()) {
if (writeProtectedUpdate) {
argumentsList.push("pkexec");
}
argumentsList.push(QFile::encodeName(binaryPath));
argumentsList.push((justRelaunch && !arguments().isEmpty())
? QFile::encodeName(arguments().first())
: binaryPath);
if (cLaunchMode() == LaunchModeAutoStart) {
argumentsList.push("-autostart");
@ -107,7 +101,7 @@ bool Launcher::launchUpdater(UpdaterLaunch action) {
argumentsList.push(QFile::encodeName(cDataFile()));
}
if (action == UpdaterLaunch::JustRelaunch) {
if (justRelaunch) {
argumentsList.push("-noupdate");
argumentsList.push("-tosettings");
if (customWorkingDir()) {
@ -121,6 +115,10 @@ bool Launcher::launchUpdater(UpdaterLaunch action) {
argumentsList.push(QFile::encodeName(cExeName()));
argumentsList.push("-exepath");
argumentsList.push(QFile::encodeName(cExeDir()));
if (!arguments().isEmpty()) {
argumentsList.push("-argv0");
argumentsList.push(QFile::encodeName(arguments().first()));
}
if (customWorkingDir()) {
argumentsList.push("-workdir_custom");
}
@ -137,11 +135,15 @@ bool Launcher::launchUpdater(UpdaterLaunch action) {
pid_t pid = fork();
switch (pid) {
case -1: return false;
case 0: execvp(args[0], args); return false;
case 0:
execvp(
writeProtectedUpdate ? args[0] : binaryPath.constData(),
args);
return false;
}
// pkexec needs an alive parent
if (action == UpdaterLaunch::PerformUpdate && cWriteProtected()) {
if (writeProtectedUpdate) {
waitpid(pid, nullptr, 0);
// launch new version in the same environment
return launchUpdater(UpdaterLaunch::JustRelaunch);

View file

@ -15,16 +15,12 @@ class Launcher : public Core::Launcher {
public:
Launcher(int argc, char *argv[]);
static Launcher &Instance();
int exec() override;
private:
void initHook() override;
bool launchUpdater(UpdaterLaunch action) override;
std::vector<std::string> _arguments;
};
} // namespace Platform

View file

@ -123,12 +123,15 @@ WaylandIntegration::~WaylandIntegration() = default;
WaylandIntegration *WaylandIntegration::Instance() {
if (!IsWayland()) return nullptr;
static std::optional<WaylandIntegration> instance(std::in_place);
base::qt_signal_producer(
QGuiApplication::platformNativeInterface(),
&QObject::destroyed
) | rpl::start_with_next([&] {
instance = std::nullopt;
}, instance->_private->lifetime);
[[maybe_unused]] static const auto Inited = [] {
base::qt_signal_producer(
QGuiApplication::platformNativeInterface(),
&QObject::destroyed
) | rpl::start_with_next([] {
instance = std::nullopt;
}, instance->_private->lifetime);
return true;
}();
if (!instance) return nullptr;
return &*instance;
}

View file

@ -8,20 +8,17 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "platform/linux/specific_linux.h"
#include "base/random.h"
#include "base/options.h"
#include "base/platform/base_platform_info.h"
#include "base/platform/linux/base_linux_glibmm_helper.h"
#include "base/platform/linux/base_linux_dbus_utilities.h"
#include "base/platform/linux/base_linux_xdp_utilities.h"
#include "platform/linux/linux_desktop_environment.h"
#include "platform/linux/linux_wayland_integration.h"
#include "platform/platform_launcher.h"
#include "lang/lang_keys.h"
#include "mainwindow.h"
#include "storage/localstorage.h"
#include "core/sandbox.h"
#include "core/launcher.h"
#include "core/application.h"
#include "core/local_url_handlers.h"
#include "core/core_settings.h"
#include "core/update_checker.h"
#include "window/window_controller.h"
@ -35,7 +32,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include <QtWidgets/QSystemTrayIcon>
#include <QtCore/QStandardPaths>
#include <QtCore/QProcess>
#include <QtCore/QAbstractEventDispatcher>
#include <kshell.h>
#include <ksandbox.h>
@ -56,57 +52,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
using namespace Platform;
using Platform::internal::WaylandIntegration;
typedef GApplication TDesktopApplication;
typedef GApplicationClass TDesktopApplicationClass;
G_DEFINE_TYPE(
TDesktopApplication,
t_desktop_application,
G_TYPE_APPLICATION)
static void t_desktop_application_class_init(
TDesktopApplicationClass *klass) {
const auto application_class = G_APPLICATION_CLASS(klass);
application_class->before_emit = [](
GApplication *application,
GVariant *platformData) {
if (Platform::IsWayland()) {
static const auto keys = {
"activation-token",
"desktop-startup-id",
};
for (const auto &key : keys) {
const char *token = nullptr;
g_variant_lookup(platformData, key, "&s", &token);
if (token) {
qputenv("XDG_ACTIVATION_TOKEN", token);
break;
}
}
}
};
application_class->add_platform_data = [](
GApplication *application,
GVariantBuilder *builder) {
if (Platform::IsWayland()) {
const auto token = qgetenv("XDG_ACTIVATION_TOKEN");
if (!token.isEmpty()) {
g_variant_builder_add(
builder,
"{sv}",
"activation-token",
g_variant_new_string(token.constData()));
qunsetenv("XDG_ACTIVATION_TOKEN");
}
}
};
}
static void t_desktop_application_init(TDesktopApplication *application) {
}
namespace Platform {
namespace {
@ -138,7 +83,7 @@ bool PortalAutostart(bool start, bool silent) {
std::vector<Glib::ustring> commandline;
commandline.push_back(cExeName().toStdString());
if (Core::Sandbox::Instance().customWorkingDir()) {
if (Core::Launcher::Instance().customWorkingDir()) {
commandline.push_back("-workdir");
commandline.push_back(cWorkingDir().toStdString());
}
@ -232,121 +177,13 @@ bool PortalAutostart(bool start, bool silent) {
return !error;
}
void LaunchGApplication() {
Glib::signal_idle().connect_once([] {
const auto appId = QGuiApplication::desktopFileName()
.chopped(8)
.toStdString();
const auto app = Glib::wrap(
G_APPLICATION(
g_object_new(
t_desktop_application_get_type(),
"application-id",
Gio::Application::id_is_valid(appId)
? appId.c_str()
: nullptr,
"flags",
G_APPLICATION_HANDLES_OPEN,
nullptr)));
app->signal_startup().connect([=] {
// GNotification
InvokeQueued(qApp, [] {
Core::App().notifications().createManager();
});
QEventLoop().exec();
app->quit();
}, true);
app->signal_activate().connect([] {
Core::Sandbox::Instance().customEnterFromEventLoop([] {
if (Core::IsAppLaunched()) {
Core::App().activate();
}
});
}, true);
app->signal_open().connect([](
const Gio::Application::type_vec_files &files,
const Glib::ustring &hint) {
Core::Sandbox::Instance().customEnterFromEventLoop([&] {
for (const auto &file : files) {
QFileOpenEvent e(
QUrl(QString::fromStdString(file->get_uri())));
QGuiApplication::sendEvent(qApp, &e);
}
});
}, true);
app->add_action("quit", [] {
Core::Sandbox::Instance().customEnterFromEventLoop([] {
Core::Quit();
});
});
using Window::Notifications::Manager;
using NotificationId = Manager::NotificationId;
using NotificationIdTuple = std::invoke_result_t<
decltype(&NotificationId::toTuple),
NotificationId*
>;
const auto notificationIdVariantType = [] {
try {
return base::Platform::MakeGlibVariant(
NotificationId().toTuple()).get_type();
} catch (...) {
return Glib::VariantType();
}
}();
app->add_action_with_parameter(
"notification-activate",
notificationIdVariantType,
[](const Glib::VariantBase &parameter) {
Core::Sandbox::Instance().customEnterFromEventLoop([&] {
try {
const auto &app = Core::App();
app.notifications().manager().notificationActivated(
NotificationId::FromTuple(
base::Platform::GlibVariantCast<
NotificationIdTuple
>(parameter)));
} catch (...) {
}
});
});
app->add_action_with_parameter(
"notification-mark-as-read",
notificationIdVariantType,
[](const Glib::VariantBase &parameter) {
Core::Sandbox::Instance().customEnterFromEventLoop([&] {
try {
const auto &app = Core::App();
app.notifications().manager().notificationReplied(
NotificationId::FromTuple(
base::Platform::GlibVariantCast<
NotificationIdTuple
>(parameter)),
{});
} catch (...) {
}
});
});
app->run(0, nullptr);
});
}
bool GenerateDesktopFile(
const QString &targetPath,
const QStringList &args = {},
bool onlyMainGroup = false,
bool silent = false) {
if (targetPath.isEmpty() || cExeName().isEmpty()) {
const auto executable = ExecutablePathForShortcuts();
if (targetPath.isEmpty() || executable.isEmpty()) {
return false;
}
@ -388,11 +225,7 @@ bool GenerateDesktopFile(
target->set_string(
group,
"TryExec",
KShell::joinArgs({
!Core::UpdaterDisabled()
? (cExeDir() + cExeName())
: cExeName()
}).replace(
KShell::joinArgs({ executable }).replace(
'\\',
qstr("\\\\")).toStdString());
}
@ -400,10 +233,8 @@ bool GenerateDesktopFile(
if (target->has_key(group, "Exec")) {
if (group == "Desktop Entry" && !args.isEmpty()) {
QStringList exec;
exec.append(!Core::UpdaterDisabled()
? (cExeDir() + cExeName())
: cExeName());
if (Core::Sandbox::Instance().customWorkingDir()) {
exec.append(executable);
if (Core::Launcher::Instance().customWorkingDir()) {
exec.append(u"-workdir"_q);
exec.append(cWorkingDir());
}
@ -423,10 +254,8 @@ bool GenerateDesktopFile(
qstr("\\")));
if (!exec.isEmpty()) {
exec[0] = !Core::UpdaterDisabled()
? (cExeDir() + cExeName())
: cExeName();
if (Core::Sandbox::Instance().customWorkingDir()) {
exec[0] = executable;
if (Core::Launcher::Instance().customWorkingDir()) {
exec.insert(1, u"-workdir"_q);
exec.insert(2, cWorkingDir());
}
@ -479,7 +308,7 @@ bool GenerateDesktopFile(
const auto d = QFile::encodeName(QDir(cWorkingDir()).absolutePath());
hashMd5Hex(d.constData(), d.size(), md5Hash);
if (!Core::Sandbox::Instance().customWorkingDir()) {
if (!Core::Launcher::Instance().customWorkingDir()) {
const auto exePath = QFile::encodeName(
cExeDir() + cExeName());
hashMd5Hex(exePath.constData(), exePath.size(), md5Hash);
@ -493,6 +322,55 @@ bool GenerateDesktopFile(
return true;
}
bool GenerateServiceFile(bool silent = false) {
const auto executable = ExecutablePathForShortcuts();
if (executable.isEmpty()) {
return false;
}
const auto targetPath = QStandardPaths::writableLocation(
QStandardPaths::GenericDataLocation) + u"/dbus-1/services/"_q;
const auto targetFile = targetPath
+ QGuiApplication::desktopFileName().chopped(8)
+ u".service"_q;
DEBUG_LOG(("App Info: placing .service file to %1").arg(targetPath));
if (!QDir(targetPath).exists()) QDir().mkpath(targetPath);
const auto target = Glib::KeyFile::create();
constexpr auto group = "D-BUS Service";
target->set_string(
group,
"Name",
QGuiApplication::desktopFileName().chopped(8).toStdString());
target->set_string(
group,
"Exec",
KShell::joinArgs({ executable }).replace(
'\\',
qstr("\\\\")).toStdString());
try {
target->save_to_file(targetFile.toStdString());
} catch (const std::exception &e) {
if (!silent) {
LOG(("App Error: %1").arg(QString::fromStdString(e.what())));
}
return false;
}
QProcess::execute(u"systemctl"_q, {
u"--user"_q,
u"reload"_q,
u"dbus"_q,
});
return true;
}
void InstallLauncher() {
static const auto DisabledByEnv = !qEnvironmentVariableIsEmpty(
"DESKTOPINTEGRATION");
@ -506,6 +384,7 @@ void InstallLauncher() {
QStandardPaths::ApplicationsLocation) + '/';
GenerateDesktopFile(applicationsPath);
GenerateServiceFile();
const auto icons = QStandardPaths::writableLocation(
QStandardPaths::GenericDataLocation) + u"/icons/"_q;
@ -615,6 +494,20 @@ bool SkipTaskbarSupported() {
return false;
}
QString ExecutablePathForShortcuts() {
if (Core::UpdaterDisabled()) {
const auto &arguments = Core::Launcher::Instance().arguments();
if (!arguments.isEmpty()) {
const auto result = QFileInfo(arguments.first()).fileName();
if (!result.isEmpty()) {
return result;
}
}
return cExeName();
}
return cExeDir() + cExeName();
}
} // namespace Platform
QString psAppDataPath() {
@ -676,7 +569,7 @@ void start() {
if (!Core::UpdaterDisabled()) {
QByteArray md5Hash(h);
if (!Launcher::Instance().customWorkingDir()) {
if (!Core::Launcher::Instance().customWorkingDir()) {
const auto exePath = QFile::encodeName(
cExeDir() + cExeName());
@ -726,6 +619,8 @@ void start() {
h,
cGUIDStr(),
u"%1"_q).toStdString());
InstallLauncher();
}
void finish() {
@ -796,17 +691,6 @@ QImage DefaultApplicationIcon() {
namespace ThirdParty {
void start() {
LOG(("Icon theme: %1").arg(QIcon::themeName()));
LOG(("Fallback icon theme: %1").arg(QIcon::fallbackThemeName()));
if (!QCoreApplication::eventDispatcher()->inherits(
"QEventDispatcherGlib")) {
g_warning("Qt is running without GLib event loop integration, "
"except various functionality to not to work.");
}
InstallLauncher();
LaunchGApplication();
}
void finish() {

View file

@ -40,6 +40,10 @@ inline uint64 ActivationWindowId(not_null<QWidget*> window) {
inline void ActivateOtherProcess(uint64 processId, uint64 windowId) {
}
inline QString ExecutablePathForShortcuts() {
return cExeDir() + cExeName();
}
namespace ThirdParty {
inline void start() {

View file

@ -46,10 +46,9 @@ bool TrayIconSupported();
bool SkipTaskbarSupported();
void WriteCrashDumpDetails();
void NewVersionLaunched(int oldVersion);
[[nodiscard]] QImage DefaultApplicationIcon();
[[nodiscard]] bool PreventsQuit(Core::QuitReason reason);
[[nodiscard]] QString ExecutablePathForShortcuts();
#if QT_VERSION < QT_VERSION_CHECK(6, 5, 0)
[[nodiscard]] std::optional<bool> IsDarkMode();

View file

@ -42,6 +42,10 @@ void SetWindowPriority(not_null<QWidget*> window, uint32 priority);
// Activate window with windowId (if found) or the largest priority.
void ActivateOtherProcess(uint64 processId, uint64 windowId);
inline QString ExecutablePathForShortcuts() {
return cExeDir() + cExeName();
}
namespace ThirdParty {
void start();

View file

@ -18,7 +18,7 @@ QByteArray gAlphaPrivateKey;
bool gManyInstance = false;
QString gKeyFile;
QString gWorkingDir, gExeDir, gExeName;
QString gWorkingDir;
QStringList gSendPaths;
QString gStartUrl;

View file

@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
#include "base/integration.h"
#include "ui/style/style_core.h"
#define DeclareReadSetting(Type, Name) extern Type g##Name; \
@ -56,11 +57,15 @@ inline void cForceWorkingDir(const QString &newDir) {
}
}
DeclareReadSetting(QString, ExeName);
DeclareReadSetting(QString, ExeDir);
inline QString cExeName() {
return base::Integration::Instance().executableName();
}
inline QString cExeDir() {
return base::Integration::Instance().executableDir();
}
DeclareSetting(QString, DialogLastPath);
DeclareSetting(QString, DialogHelperPath);
inline const QString &cDialogHelperPathFinal() {
inline QString cDialogHelperPathFinal() {
return cDialogHelperPath().isEmpty() ? cExeDir() : cDialogHelperPath();
}

View file

@ -32,6 +32,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "window/window_session_controller.h"
#include "lang/lang_keys.h"
#include "core/update_checker.h"
#include "core/launcher.h"
#include "core/application.h"
#include "tray.h"
#include "storage/localstorage.h"
@ -224,7 +225,7 @@ void SetupUpdate(
return (toggled != cInstallBetaVersion());
}) | rpl::start_with_next([=](bool toggled) {
cSetInstallBetaVersion(toggled);
Core::App().writeInstallBetaVersionsSetting();
Core::Launcher::Instance().writeInstallBetaVersionsSetting();
Core::UpdateChecker checker;
checker.stop();

View file

@ -28,7 +28,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "window/window_session_controller.h"
#include "storage/storage_media_prepare.h"
#include "storage/localimageloader.h"
#include "core/sandbox.h"
#include "core/launcher.h"
#include "core/application.h"
#include "core/core_settings.h"
#include "main/main_session.h"
@ -138,7 +138,7 @@ void EditInfoBox::setInnerFocus() {
}
uint32 OccupationTag() {
return uint32(Core::Sandbox::Instance().installationTag() & 0xFFFFFFFF);
return uint32(Core::Launcher::Instance().installationTag() & 0xFFFFFFFF);
}
QString NormalizeName(QString name) {
@ -268,7 +268,7 @@ Helper::Helper(not_null<Main::Session*> session)
}).fail([=] {
setSupportName(
u"[rand^"_q
+ QString::number(Core::Sandbox::Instance().installationTag())
+ QString::number(Core::Launcher::Instance().installationTag())
+ ']');
}).send();
}

View file

@ -7,7 +7,7 @@
{%- set OPENSSL_PREFIX = "/usr/local/desktop-app/openssl-1.1.1" -%}
{%- set CMAKE_VER = "3.26.3" -%}
{%- set CMAKE_FILE = "cmake-" ~ CMAKE_VER ~ "-Linux-x86_64.sh" -%}
{%- set CFLAGS_DEBUG = "-g -pipe -fPIC -fstack-protector-all -fstack-clash-protection -D_GLIBCXX_ASSERTIONS" -%}
{%- set CFLAGS_DEBUG = "-g -pipe -fPIC -fstack-protector-all -fstack-clash-protection -fcf-protection -D_GLIBCXX_ASSERTIONS" -%}
{%- set CFLAGS_LTO = "-flto=auto -ffat-lto-objects" -%}
{%- set LibrariesPath = "/usr/src/Libraries" -%}
@ -52,14 +52,14 @@ FROM builder-base AS builder
ENV AR gcc-ar
ENV RANLIB gcc-ranlib
ENV NM gcc-nm
ENV CFLAGS {% if DEBUG %}-g{% endif %} -O3 {% if LTO %}{{ CFLAGS_LTO }}{% endif %} -pipe -fPIC -fstack-protector-all -fstack-clash-protection -DNDEBUG -D_FORTIFY_SOURCE=2 -D_GLIBCXX_ASSERTIONS
ENV CFLAGS {% if DEBUG %}-g{% endif %} -O3 {% if LTO %}{{ CFLAGS_LTO }}{% endif %} -pipe -fPIC -fstack-protector-all -fstack-clash-protection -fcf-protection -DNDEBUG -D_FORTIFY_SOURCE=2 -D_GLIBCXX_ASSERTIONS
ENV CXXFLAGS $CFLAGS
FROM builder AS patches
RUN git init patches \
&& cd patches \
&& git remote add origin {{ GIT }}/desktop-app/patches.git \
&& git fetch --depth=1 origin a1b912c90eaab470ef283622a8f890ee6264dae7 \
&& git fetch --depth=1 origin 963f5b0c2a57f7e90239e64c9e14ed5f043e637e \
&& git reset --hard FETCH_HEAD \
&& rm -rf .git
@ -729,10 +729,6 @@ RUN git clone -b {{ QT_TAG }} --depth=1 https://code.qt.io/qt/qt5.git qt_{{ QT }
&& git submodule update --init --recursive --depth=1 qtbase qtdeclarative qtwayland qtimageformats qtsvg qtshadertools \
&& cd qtbase \
&& find ../../patches/qtbase_{{ QT }} -type f -print0 | sort -z | xargs -r0 git apply \
&& cd ../qtdeclarative \
&& sed -i '/add_subdirectory(quickcontrols)/d' src/CMakeLists.txt \
&& sed -i '/add_subdirectory(quickdialogs)/d' src/CMakeLists.txt \
&& sed -i '/add_subdirectory(quicknativestyle)/d' src/CMakeLists.txt \
&& cd .. \
&& ./configure -prefix "{{ QT_PREFIX }}" \
CMAKE_BUILD_TYPE=None \

View file

@ -1,4 +1,5 @@
#!/bin/bash
set -e
cd Telegram
./configure.sh "$@"

View file

@ -3,10 +3,13 @@ from os import environ
from os.path import dirname
from jinja2 import Environment, FileSystemLoader
def checkEnv(envName, defaultValue):
return bool(len(environ[envName])) if envName in environ else defaultValue
def main():
print(Environment(loader=FileSystemLoader(dirname(__file__))).get_template("Dockerfile").render(
DEBUG=bool(len(environ["DEBUG"])) if "DEBUG" in environ else True,
LTO=bool(len(environ["LTO"])) if "LTO" in environ else True,
DEBUG=checkEnv("DEBUG", True),
LTO=checkEnv("LTO", True),
))
if __name__ == '__main__':

View file

@ -673,7 +673,7 @@ mac:
stage('dav1d', """
win:
git clone -b 1.0.0 --depth 1 https://code.videolan.org/videolan/dav1d.git
git clone -b 1.2.1 --depth 1 https://code.videolan.org/videolan/dav1d.git
cd dav1d
depends:python/Scripts/activate.bat
%THIRDPARTY_DIR%\\python\\Scripts\\activate.bat
@ -710,7 +710,7 @@ release:
stage('libde265', """
win:
git clone --depth 1 -b v1.0.11 https://github.com/strukturag/libde265.git
git clone --depth 1 -b v1.0.12 https://github.com/strukturag/libde265.git
cd libde265
cmake . ^
-A %WIN32X64% ^
@ -734,7 +734,7 @@ release:
stage('libheif', """
win:
git clone --depth 1 -b v1.15.1 https://github.com/strukturag/libheif.git
git clone --depth 1 -b v1.16.2 https://github.com/strukturag/libheif.git
cd libheif
%THIRDPARTY_DIR%\\msys64\\usr\\bin\\sed.exe -i 's/LIBHEIF_EXPORTS/LIBDE265_STATIC_BUILD/g' libheif/CMakeLists.txt
%THIRDPARTY_DIR%\\msys64\\usr\\bin\\sed.exe -i 's/HAVE_VISIBILITY/LIBHEIF_STATIC_BUILD/g' libheif/CMakeLists.txt
@ -762,7 +762,7 @@ release:
stage('libjxl', """
win:
git clone -b v0.8.1 --depth 1 --recursive --shallow-submodules https://github.com/libjxl/libjxl.git
git clone -b v0.8.2 --depth 1 --recursive --shallow-submodules https://github.com/libjxl/libjxl.git
cd libjxl
cmake . ^
-A %WIN32X64% ^

View file

@ -63,20 +63,11 @@ def getOutput(command):
sys.exit(1)
return output.decode('utf-8')
def prepareSources():
workpath = os.getcwd()
os.chdir('../..')
rootpath = os.getcwd()
finalpath = rootpath + '/out/Release/sources.tar'
if os.path.exists(finalpath):
os.remove(finalpath)
if os.path.exists(finalpath + '.gz'):
os.remove(finalpath + '.gz')
tmppath = rootpath + '/out/Release/tmp.tar'
print('Preparing source tarball...')
if (call(('git archive --prefix=tdesktop-' + version + '-full/ -o ' + finalpath + ' v' + version).split()) != 0):
os.remove(finalpath)
sys.exit(1)
def invoke(command):
return call(command.split()) == 0
def appendSubmodules(appendTo, root, rootRevision):
startpath = os.getcwd()
lines = getOutput('git submodule foreach').split('\n')
for line in lines:
if len(line) == 0:
@ -84,23 +75,48 @@ def prepareSources():
match = re.match(r"^Entering '([^']+)'$", line)
if not match:
print('Bad line: ' + line)
sys.exit(1)
return False
path = match.group(1)
revision = getOutput('git rev-parse v' + version + ':' + path).split('\n')[0]
subroot = root + '/' + path
revision = getOutput('git rev-parse ' + rootRevision + ':' + path).split('\n')[0]
print('Adding submodule ' + path + '...')
os.chdir(path)
if (call(('git archive --prefix=tdesktop-' + version + '-full/' + path + '/ ' + revision + ' -o ' + tmppath).split()) != 0):
os.remove(finalpath)
os.remove(tmppath)
sys.exit(1)
if (call(('gtar --concatenate --file=' + finalpath + ' ' + tmppath).split()) != 0):
os.remove(finalpath)
os.remove(tmppath)
sys.exit(1)
os.remove(tmppath)
os.chdir(rootpath)
tmppath = appendTo + '_tmp'
if not invoke('git archive --prefix=' + subroot + '/ ' + revision + ' -o ' + tmppath + '.tar'):
os.remove(appendTo + '.tar')
os.remove(tmppath + '.tar')
return False
if not appendSubmodules(tmppath, subroot, revision):
return False
if not invoke('gtar --concatenate --file=' + appendTo + '.tar ' + tmppath + '.tar'):
os.remove(appendTo + '.tar')
os.remove(tmppath + '.tar')
return False
os.remove(tmppath + '.tar')
os.chdir(startpath)
return True
def prepareSources():
workpath = os.getcwd()
os.chdir('../..')
rootpath = os.getcwd()
finalpart = rootpath + '/out/Release/sources'
finalpath = finalpart + '.tar'
if os.path.exists(finalpath):
os.remove(finalpath)
if os.path.exists(finalpath + '.gz'):
os.remove(finalpath + '.gz')
tmppath = rootpath + '/out/Release/tmp.tar'
print('Preparing source tarball...')
revision = 'v' + version
targetRoot = 'tdesktop-' + version + '-full';
if not invoke('git archive --prefix=' + targetRoot + '/ -o ' + finalpath + ' ' + revision):
os.remove(finalpath)
sys.exit(1)
if not appendSubmodules(finalpart, targetRoot, revision):
sys.exit(1)
print('Compressing...')
if (call(('gzip -9 ' + finalpath).split()) != 0):
if not invoke('gzip -9 ' + finalpath):
os.remove(finalpath)
sys.exit(1)
os.chdir(workpath)
@ -254,12 +270,12 @@ if r.status_code == 404:
checkResponseCode(r, 201)
tagname = 'v' + version
call("git fetch origin".split())
invoke("git fetch origin")
if stable == 1:
call("git push launchpad {}:master".format(tagname).split())
invoke("git push launchpad {}:master".format(tagname))
else:
call("git push launchpad {}:beta".format(tagname).split())
call("git push --tags launchpad".split())
invoke("git push launchpad {}:beta".format(tagname))
invoke("git push --tags launchpad")
r = requests.get(url + 'repos/telegramdesktop/tdesktop/releases/tags/v' + version)
checkResponseCode(r, 200)
@ -307,9 +323,8 @@ for file in files:
checkResponseCode(r, 201)
print('Success! Removing.')
return_code = call(["rm", file_path])
if return_code != 0:
print('Bad rm code: ' + str(return_code))
if not invoke('rm ' + file_path):
print('Bad rm return code :(')
sys.exit(1)
sys.exit()

View file

@ -1,7 +1,7 @@
AppVersion 4008003
AppVersion 4008004
AppVersionStrMajor 4.8
AppVersionStrSmall 4.8.3
AppVersionStr 4.8.3
AppVersionStrSmall 4.8.4
AppVersionStr 4.8.4
BetaChannel 0
AlphaVersion 0
AppVersionOriginal 4.8.3
AppVersionOriginal 4.8.4

View file

@ -1,3 +1,7 @@
4.8.4 (13.06.23)
- Fix opening links on Linux.
4.8.3 (31.05.23)
- Fix main window focus from notifications with disabled animations.

View file

@ -13,7 +13,7 @@ You will require **api_id** and **api_hash** to access the Telegram API servers.
Go to ***BuildPath*** and run
ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
brew install git automake cmake wget pkg-config gnu-tar
brew install git automake cmake wget pkg-config gnu-tar ninja
sudo xcode-select -s /Applications/Xcode.app/Contents/Developer

View file

@ -11,6 +11,7 @@ Categories=Chat;Network;InstantMessaging;Qt;
MimeType=x-scheme-handler/tg;
Keywords=tg;chat;im;messaging;messenger;sms;tdesktop;
Actions=quit;
DBusActivatable=true
SingleMainWindow=true
X-GNOME-UsesNotifications=true
X-GNOME-SingleWindow=true

View file

@ -0,0 +1,3 @@
[D-BUS Service]
Name=org.telegram.desktop
Exec=telegram-desktop

View file

@ -28,9 +28,11 @@ apps:
- camera
- desktop
- desktop-legacy
- gsettings
- hardware-observe
- home
- network
- network-bind
- network-status
- opengl
- removable-media
@ -52,7 +54,6 @@ plugs:
mount-host-font-cache: false
# Support for common GTK themes
# https://forum.snapcraft.io/t/how-to-use-the-system-gtk-theme-via-the-gtk-common-themes-snap/6235
gsettings:
gtk-3-themes:
interface: content
target: $SNAP/data-dir/themes