| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849 |
- /*
- This file is part of Telegram Desktop,
- the official desktop application for the Telegram messaging service.
- For license and copyright information please follow this link:
- https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
- */
- #include "platform/linux/specific_linux.h"
- #include "base/openssl_help.h"
- #include "base/random.h"
- #include "base/platform/base_platform_info.h"
- #include "base/platform/linux/base_linux_dbus_utilities.h"
- #include "base/platform/linux/base_linux_xdp_utilities.h"
- #include "lang/lang_keys.h"
- #include "mainwindow.h"
- #include "storage/localstorage.h"
- #include "core/launcher.h"
- #include "core/sandbox.h"
- #include "core/application.h"
- #include "core/core_settings.h"
- #include "core/update_checker.h"
- #include "window/window_controller.h"
- #include "webview/platform/linux/webview_linux_webkitgtk.h"
- #ifndef DESKTOP_APP_DISABLE_X11_INTEGRATION
- #include "base/platform/linux/base_linux_xcb_utilities.h"
- #endif // !DESKTOP_APP_DISABLE_X11_INTEGRATION
- #include <QtWidgets/QApplication>
- #include <QtWidgets/QSystemTrayIcon>
- #include <QtCore/QStandardPaths>
- #include <QtCore/QProcess>
- #include <kshell.h>
- #include <ksandbox.h>
- #include <xdgdbus/xdgdbus.hpp>
- #include <xdpbackground/xdpbackground.hpp>
- #include <xdprequest/xdprequest.hpp>
- #include <sys/stat.h>
- #include <sys/types.h>
- #include <sys/un.h>
- #include <cstdlib>
- #include <unistd.h>
- #include <dirent.h>
- #include <pwd.h>
- #include <iostream>
- namespace {
- using namespace gi::repository;
- namespace GObject = gi::repository::GObject;
- using namespace Platform;
- void PortalAutostart(bool enabled, Fn<void(bool)> done) {
- const auto executable = ExecutablePathForShortcuts();
- if (executable.isEmpty()) {
- if (done) {
- done(false);
- }
- return;
- }
- XdpBackground::BackgroundProxy::new_for_bus(
- Gio::BusType::SESSION_,
- Gio::DBusProxyFlags::NONE_,
- base::Platform::XDP::kService,
- base::Platform::XDP::kObjectPath,
- [=](GObject::Object, Gio::AsyncResult res) {
- auto proxy = XdpBackground::BackgroundProxy::new_for_bus_finish(
- res);
- if (!proxy) {
- if (done) {
- Gio::DBusErrorNS_::strip_remote_error(proxy.error());
- LOG(("Portal Autostart Error: %1").arg(
- proxy.error().message_().c_str()));
- done(false);
- }
- return;
- }
- auto interface = XdpBackground::Background(*proxy);
- const auto handleToken = "tdesktop"
- + std::to_string(base::RandomValue<uint>());
- auto uniqueName = std::string(
- proxy->get_connection().get_unique_name());
- uniqueName.erase(0, 1);
- uniqueName.replace(uniqueName.find('.'), 1, 1, '_');
- const auto parent = []() -> QPointer<QWidget> {
- const auto active = Core::App().activeWindow();
- if (!active) {
- return nullptr;
- }
- return active->widget().get();
- }();
- const auto window = std::make_shared<base::unique_qptr<QWidget>>(
- std::in_place,
- parent);
- auto &raw = **window;
- raw.setAttribute(Qt::WA_DontShowOnScreen);
- raw.setWindowFlag(Qt::Window);
- raw.setWindowModality(Qt::WindowModal);
- raw.show();
- XdpRequest::RequestProxy::new_(
- proxy->get_connection(),
- Gio::DBusProxyFlags::NONE_,
- base::Platform::XDP::kService,
- base::Platform::XDP::kObjectPath
- + std::string("/request/")
- + uniqueName
- + '/'
- + handleToken,
- nullptr,
- [=](GObject::Object, Gio::AsyncResult res) mutable {
- auto requestProxy = XdpRequest::RequestProxy::new_finish(
- res);
- if (!requestProxy) {
- if (done) {
- Gio::DBusErrorNS_::strip_remote_error(
- requestProxy.error());
- LOG(("Portal Autostart Error: %1").arg(
- requestProxy.error().message_().c_str()));
- done(false);
- }
- return;
- }
- auto request = XdpRequest::Request(*requestProxy);
- const auto signalId = std::make_shared<ulong>();
- *signalId = request.signal_response().connect([=](
- XdpRequest::Request,
- guint response,
- GLib::Variant) mutable {
- auto &sandbox = Core::Sandbox::Instance();
- sandbox.customEnterFromEventLoop([&] {
- (void)window; // don't destroy until finish
- if (response) {
- if (done) {
- LOG(("Portal Autostart Error: "
- "Request denied"));
- done(false);
- }
- } else if (done) {
- done(enabled);
- }
- request.disconnect(*signalId);
- });
- });
- std::vector<std::string> commandline;
- commandline.push_back(executable.toStdString());
- if (Core::Launcher::Instance().customWorkingDir()) {
- commandline.push_back("-workdir");
- commandline.push_back(cWorkingDir().toStdString());
- }
- commandline.push_back("-autostart");
- interface.call_request_background(
- base::Platform::XDP::ParentWindowID(parent
- ? parent->windowHandle()
- : nullptr),
- GLib::Variant::new_array({
- GLib::Variant::new_dict_entry(
- GLib::Variant::new_string("handle_token"),
- GLib::Variant::new_variant(
- GLib::Variant::new_string(handleToken))),
- GLib::Variant::new_dict_entry(
- GLib::Variant::new_string("reason"),
- GLib::Variant::new_variant(
- GLib::Variant::new_string(
- tr::lng_settings_auto_start(tr::now)
- .toStdString()))),
- GLib::Variant::new_dict_entry(
- GLib::Variant::new_string("autostart"),
- GLib::Variant::new_variant(
- GLib::Variant::new_boolean(enabled))),
- GLib::Variant::new_dict_entry(
- GLib::Variant::new_string("commandline"),
- GLib::Variant::new_variant(
- GLib::Variant::new_strv(commandline))),
- GLib::Variant::new_dict_entry(
- GLib::Variant::new_string("dbus-activatable"),
- GLib::Variant::new_variant(
- GLib::Variant::new_boolean(false))),
- }),
- [=](GObject::Object, Gio::AsyncResult res) mutable {
- auto &sandbox = Core::Sandbox::Instance();
- sandbox.customEnterFromEventLoop([&] {
- const auto result =
- interface.call_request_background_finish(
- res);
- if (!result) {
- if (done) {
- const auto &error = result.error();
- Gio::DBusErrorNS_::strip_remote_error(
- error);
- LOG(("Portal Autostart Error: %1").arg(
- error.message_().c_str()));
- done(false);
- }
- request.disconnect(*signalId);
- }
- });
- });
- });
- });
- }
- bool GenerateDesktopFile(
- const QString &targetPath,
- const QStringList &args = {},
- bool onlyMainGroup = false,
- bool silent = false) {
- const auto executable = ExecutablePathForShortcuts();
- if (targetPath.isEmpty() || executable.isEmpty()) {
- return false;
- }
- DEBUG_LOG(("App Info: placing .desktop file to %1").arg(targetPath));
- if (!QDir(targetPath).exists()) QDir().mkpath(targetPath);
- const auto sourceFile = u":/misc/org.telegram.desktop.desktop"_q;
- const auto targetFile = targetPath
- + QGuiApplication::desktopFileName()
- + u".desktop"_q;
- const auto sourceText = [&] {
- QFile source(sourceFile);
- if (source.open(QIODevice::ReadOnly)) {
- return source.readAll().toStdString();
- }
- return std::string();
- }();
- if (sourceText.empty()) {
- if (!silent) {
- LOG(("App Error: Could not open '%1' for read").arg(sourceFile));
- }
- return false;
- }
- auto target = GLib::KeyFile::new_();
- const auto loaded = target.load_from_data(
- sourceText,
- -1,
- GLib::KeyFileFlags::KEEP_COMMENTS_
- | GLib::KeyFileFlags::KEEP_TRANSLATIONS_);
- if (!loaded) {
- if (!silent) {
- LOG(("App Error: %1").arg(loaded.error().message_().c_str()));
- }
- return false;
- }
- for (const auto &group : target.get_groups(nullptr)) {
- if (onlyMainGroup && group != "Desktop Entry") {
- const auto removed = target.remove_group(group);
- if (!removed) {
- if (!silent) {
- LOG(("App Error: %1").arg(
- removed.error().message_().c_str()));
- }
- return false;
- }
- continue;
- }
- if (target.has_key(group, "TryExec", nullptr)) {
- target.set_string(
- group,
- "TryExec",
- KShell::joinArgs({ executable }).replace(
- '\\',
- qstr("\\\\")).toStdString());
- }
- if (target.has_key(group, "Exec", nullptr)) {
- if (group == "Desktop Entry" && !args.isEmpty()) {
- QStringList exec;
- exec.append(executable);
- if (Core::Launcher::Instance().customWorkingDir()) {
- exec.append(u"-workdir"_q);
- exec.append(cWorkingDir());
- }
- exec.append(args);
- target.set_string(
- group,
- "Exec",
- KShell::joinArgs(exec).replace(
- '\\',
- qstr("\\\\")).toStdString());
- } else {
- auto exec = KShell::splitArgs(
- QString::fromStdString(
- target.get_string(group, "Exec", nullptr)
- ).replace(
- qstr("\\\\"),
- qstr("\\")));
- if (!exec.isEmpty()) {
- exec[0] = executable;
- if (Core::Launcher::Instance().customWorkingDir()) {
- exec.insert(1, u"-workdir"_q);
- exec.insert(2, cWorkingDir());
- }
- target.set_string(
- group,
- "Exec",
- KShell::joinArgs(exec).replace(
- '\\',
- qstr("\\\\")).toStdString());
- }
- }
- }
- }
- if (!args.isEmpty()) {
- target.remove_key("Desktop Entry", "DBusActivatable");
- }
- const auto saved = target.save_to_file(targetFile.toStdString());
- if (!saved) {
- if (!silent) {
- LOG(("App Error: %1").arg(saved.error().message_().c_str()));
- }
- return false;
- }
- QFile::setPermissions(
- targetFile,
- QFile::permissions(targetFile)
- | QFileDevice::ExeOwner
- | QFileDevice::ExeGroup
- | QFileDevice::ExeOther);
- if (!Core::UpdaterDisabled()) {
- DEBUG_LOG(("App Info: removing old .desktop files"));
- QFile::remove(u"%1telegram.desktop"_q.arg(targetPath));
- QFile::remove(u"%1telegramdesktop.desktop"_q.arg(targetPath));
- const auto appimagePath = u"file://%1%2"_q.arg(
- cExeDir(),
- cExeName()).toUtf8();
- char md5Hash[33] = { 0 };
- hashMd5Hex(
- appimagePath.constData(),
- appimagePath.size(),
- md5Hash);
- QFile::remove(u"%1appimagekit_%2-%3.desktop"_q.arg(
- targetPath,
- md5Hash,
- AppName.utf16().replace(' ', '_')));
- const auto d = QFile::encodeName(QDir(cWorkingDir()).absolutePath());
- hashMd5Hex(d.constData(), d.size(), md5Hash);
- if (!Core::Launcher::Instance().customWorkingDir()) {
- QFile::remove(u"%1org.telegram.desktop._%2.desktop"_q.arg(
- targetPath,
- md5Hash));
- const auto exePath = QFile::encodeName(
- cExeDir() + cExeName());
- hashMd5Hex(exePath.constData(), exePath.size(), md5Hash);
- }
- QFile::remove(u"%1org.telegram.desktop.%2.desktop"_q.arg(
- targetPath,
- md5Hash));
- }
- 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()
- + u".service"_q;
- DEBUG_LOG(("App Info: placing D-Bus service file to %1").arg(targetPath));
- if (!QDir(targetPath).exists()) QDir().mkpath(targetPath);
- auto target = GLib::KeyFile::new_();
- constexpr auto group = "D-BUS Service";
- target.set_string(
- group,
- "Name",
- QGuiApplication::desktopFileName().toStdString());
- QStringList exec;
- exec.append(executable);
- if (Core::Launcher::Instance().customWorkingDir()) {
- exec.append(u"-workdir"_q);
- exec.append(cWorkingDir());
- }
- target.set_string(
- group,
- "Exec",
- KShell::joinArgs(exec).toStdString());
- const auto saved = target.save_to_file(targetFile.toStdString());
- if (!saved) {
- if (!silent) {
- LOG(("App Error: %1").arg(saved.error().message_().c_str()));
- }
- return false;
- }
- if (!Core::UpdaterDisabled()
- && !Core::Launcher::Instance().customWorkingDir()) {
- DEBUG_LOG(("App Info: removing old D-Bus service files"));
- char md5Hash[33] = { 0 };
- const auto d = QFile::encodeName(QDir(cWorkingDir()).absolutePath());
- hashMd5Hex(d.constData(), d.size(), md5Hash);
- QFile::remove(u"%1org.telegram.desktop._%2.service"_q.arg(
- targetPath,
- md5Hash));
- }
- XdgDBus::DBusProxy::new_for_bus(
- Gio::BusType::SESSION_,
- Gio::DBusProxyFlags::NONE_,
- base::Platform::DBus::kService,
- base::Platform::DBus::kObjectPath,
- [=](GObject::Object, Gio::AsyncResult res) {
- auto interface = XdgDBus::DBus(
- XdgDBus::DBusProxy::new_for_bus_finish(res, nullptr));
- if (!interface) {
- return;
- }
- interface.call_reload_config(nullptr);
- });
- return true;
- }
- void InstallLauncher() {
- static const auto DisabledByEnv = !qEnvironmentVariableIsEmpty(
- "DESKTOPINTEGRATION");
- // don't update desktop file for alpha version or if updater is disabled
- if (cAlphaVersion() || Core::UpdaterDisabled() || DisabledByEnv) {
- return;
- }
- const auto applicationsPath = QStandardPaths::writableLocation(
- QStandardPaths::ApplicationsLocation) + '/';
- GenerateDesktopFile(applicationsPath);
- GenerateServiceFile();
- const auto icons = QStandardPaths::writableLocation(
- QStandardPaths::GenericDataLocation) + u"/icons/"_q;
- const auto appIcons = icons + u"/hicolor/256x256/apps/"_q;
- if (!QDir(appIcons).exists()) QDir().mkpath(appIcons);
- const auto icon = appIcons + ApplicationIconName() + u".png"_q;
- QFile::remove(icon);
- QFile::remove(icons + u"telegram.png"_q);
- if (QFile::copy(u":/gui/art/logo_256.png"_q, icon)) {
- DEBUG_LOG(("App Info: Icon copied to '%1'").arg(icon));
- }
- const auto symbolicIcons = icons + u"/hicolor/symbolic/apps/"_q;
- if (!QDir().exists(symbolicIcons)) QDir().mkpath(symbolicIcons);
- const auto monochromeIcons = {
- QString(),
- u"attention"_q,
- u"mute"_q,
- };
- for (const auto &icon : monochromeIcons) {
- QFile::copy(
- u":/gui/icons/tray/monochrome%1.svg"_q.arg(
- !icon.isEmpty() ? u"_"_q + icon : QString()),
- symbolicIcons
- + ApplicationIconName()
- + (!icon.isEmpty() ? u"-"_q + icon : QString())
- + u"-symbolic.svg"_q);
- }
- QProcess::execute("update-desktop-database", {
- applicationsPath
- });
- }
- [[nodiscard]] QByteArray HashForSocketPath() {
- constexpr auto kHashForSocketPathLength = 24;
- const auto binary = openssl::Sha256(
- bytes::make_span(Core::Launcher::Instance().instanceHash()));
- const auto base64 = QByteArray(
- reinterpret_cast<const char*>(binary.data()),
- binary.size()).toBase64(QByteArray::Base64UrlEncoding);
- return base64.mid(0, kHashForSocketPathLength);
- }
- } // namespace
- namespace Platform {
- void SetApplicationIcon(const QIcon &icon) {
- QApplication::setWindowIcon(icon);
- }
- QString SingleInstanceLocalServerName(const QString &hash) {
- #if defined Q_OS_LINUX && QT_VERSION >= QT_VERSION_CHECK(6, 2, 0)
- if (KSandbox::isSnap()) {
- return u"snap."_q
- + qEnvironmentVariable("SNAP_INSTANCE_NAME")
- + '.'
- + hash;
- }
- return hash + '-' + QCoreApplication::applicationName();
- #else // Q_OS_LINUX && Qt >= 6.2.0
- return QDir::tempPath()
- + '/'
- + hash
- + '-'
- + QCoreApplication::applicationName();
- #endif // !Q_OS_LINUX || Qt < 6.2.0
- }
- #if QT_VERSION < QT_VERSION_CHECK(6, 5, 0)
- std::optional<bool> IsDarkMode() {
- auto result = base::Platform::XDP::ReadSetting(
- "org.freedesktop.appearance",
- "color-scheme");
- return result.has_value()
- ? std::make_optional(result->get_uint32() == 1)
- : std::nullopt;
- }
- #endif // Qt < 6.5.0
- bool AutostartSupported() {
- return true;
- }
- void AutostartToggle(bool enabled, Fn<void(bool)> done) {
- if (KSandbox::isFlatpak()) {
- PortalAutostart(enabled, done);
- return;
- }
- const auto success = [&] {
- const auto autostart = QStandardPaths::writableLocation(
- QStandardPaths::GenericConfigLocation)
- + u"/autostart/"_q;
- if (!enabled) {
- return QFile::remove(
- autostart
- + QGuiApplication::desktopFileName()
- + u".desktop"_q);
- }
- return GenerateDesktopFile(
- autostart,
- { u"-autostart"_q },
- true,
- !done);
- }();
- if (done) {
- done(enabled && success);
- }
- }
- bool AutostartSkip() {
- return !cAutoStart();
- }
- bool TrayIconSupported() {
- return QSystemTrayIcon::isSystemTrayAvailable();
- }
- bool SkipTaskbarSupported() {
- #ifndef DESKTOP_APP_DISABLE_X11_INTEGRATION
- if (IsX11()) {
- return base::Platform::XCB::IsSupportedByWM(
- base::Platform::XCB::Connection(),
- "_NET_WM_STATE_SKIP_TASKBAR");
- }
- #endif // !DESKTOP_APP_DISABLE_X11_INTEGRATION
- 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() {
- // Previously we used ~/.TelegramDesktop, so look there first.
- // If we find data there, we should still use it.
- auto home = QDir::homePath();
- if (!home.isEmpty()) {
- auto oldPath = home + u"/.TelegramDesktop/"_q;
- auto oldSettingsBase = oldPath + u"tdata/settings"_q;
- if (QFile::exists(oldSettingsBase + '0')
- || QFile::exists(oldSettingsBase + '1')
- || QFile::exists(oldSettingsBase + 's')) {
- return oldPath;
- }
- }
- return QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation) + '/';
- }
- void psDoCleanup() {
- try {
- Platform::AutostartToggle(false);
- psSendToMenu(false, true);
- } catch (...) {
- }
- }
- int psCleanup() {
- psDoCleanup();
- return 0;
- }
- void psDoFixPrevious() {
- }
- int psFixPrevious() {
- psDoFixPrevious();
- return 0;
- }
- namespace Platform {
- void start() {
- QGuiApplication::setDesktopFileName([&] {
- if (KSandbox::isFlatpak()) {
- return qEnvironmentVariable("FLATPAK_ID");
- }
- if (KSandbox::isSnap()) {
- return qEnvironmentVariable("SNAP_INSTANCE_NAME")
- + '_'
- + cExeName();
- }
- if (!Core::UpdaterDisabled()) {
- return u"org.telegram.desktop._%1"_q.arg(
- Core::Launcher::Instance().instanceHash().constData());
- }
- return u"org.telegram.desktop"_q;
- }());
- LOG(("App ID: %1").arg(QGuiApplication::desktopFileName()));
- if (!qEnvironmentVariableIsSet("XDG_ACTIVATION_TOKEN")
- && qEnvironmentVariableIsSet("DESKTOP_STARTUP_ID")) {
- qputenv("XDG_ACTIVATION_TOKEN", qgetenv("DESKTOP_STARTUP_ID"));
- }
- qputenv("PULSE_PROP_application.name", AppName.utf8());
- qputenv(
- "PULSE_PROP_application.icon_name",
- ApplicationIconName().toUtf8());
- GLib::set_prgname(cExeName().toStdString());
- GLib::set_application_name(AppName.data());
- Webview::WebKitGTK::SetSocketPath(u"%1/%2-%3-webview-%4"_q.arg(
- QDir::tempPath(),
- HashForSocketPath(),
- u"TD"_q,//QCoreApplication::applicationName(), - make path smaller.
- u"%1"_q).toStdString());
- InstallLauncher();
- }
- void finish() {
- }
- PermissionStatus GetPermissionStatus(PermissionType type) {
- return PermissionStatus::Granted;
- }
- void RequestPermission(PermissionType type, Fn<void(PermissionStatus)> resultCallback) {
- resultCallback(PermissionStatus::Granted);
- }
- void OpenSystemSettingsForPermission(PermissionType type) {
- }
- bool OpenSystemSettings(SystemSettingsType type) {
- if (type == SystemSettingsType::Audio) {
- struct Command {
- QString command;
- QStringList arguments;
- };
- auto options = std::vector<Command>();
- const auto add = [&](const char *option, const char *arg = nullptr) {
- auto command = Command{ .command = option };
- if (arg) {
- command.arguments.push_back(arg);
- }
- options.push_back(std::move(command));
- };
- add("unity-control-center", "sound");
- add("kcmshell6", "kcm_pulseaudio");
- add("kcmshell5", "kcm_pulseaudio");
- add("kcmshell4", "phonon");
- add("gnome-control-center", "sound");
- add("cinnamon-settings", "sound");
- add("mate-volume-control");
- add("pavucontrol-qt");
- add("pavucontrol");
- add("alsamixergui");
- return ranges::any_of(options, [](const Command &command) {
- return QProcess::startDetached(
- command.command,
- command.arguments);
- });
- }
- return true;
- }
- void NewVersionLaunched(int oldVersion) {
- if (oldVersion <= 4001001 && cAutoStart()) {
- AutostartToggle(true);
- }
- }
- QImage DefaultApplicationIcon() {
- return Window::Logo();
- }
- QString ApplicationIconName() {
- static const auto Result = KSandbox::isSnap()
- ? u"snap.%1."_q.arg(qEnvironmentVariable("SNAP_INSTANCE_NAME"))
- : QGuiApplication::desktopFileName().remove(
- u"._"_q + Core::Launcher::Instance().instanceHash());
- return Result;
- }
- namespace ThirdParty {
- void start() {
- }
- } // namespace ThirdParty
- } // namespace Platform
- void psSendToMenu(bool send, bool silent) {
- }
- bool linuxMoveFile(const char *from, const char *to) {
- FILE *ffrom = fopen(from, "rb"), *fto = fopen(to, "wb");
- if (!ffrom) {
- if (fto) fclose(fto);
- return false;
- }
- if (!fto) {
- fclose(ffrom);
- return false;
- }
- static const int BufSize = 65536;
- char buf[BufSize];
- while (size_t size = fread(buf, 1, BufSize, ffrom)) {
- fwrite(buf, 1, size, fto);
- }
- struct stat fst; // from http://stackoverflow.com/questions/5486774/keeping-fileowner-and-permissions-after-copying-file-in-c
- //let's say this wont fail since you already worked OK on that fp
- if (fstat(fileno(ffrom), &fst) != 0) {
- fclose(ffrom);
- fclose(fto);
- return false;
- }
- //update to the same uid/gid
- if (fchown(fileno(fto), fst.st_uid, fst.st_gid) != 0) {
- fclose(ffrom);
- fclose(fto);
- return false;
- }
- //update the permissions
- if (fchmod(fileno(fto), fst.st_mode) != 0) {
- fclose(ffrom);
- fclose(fto);
- return false;
- }
- fclose(ffrom);
- fclose(fto);
- if (unlink(from)) {
- return false;
- }
- return true;
- }
- bool psLaunchMaps(const Data::LocationPoint &point) {
- return false;
- }
|