From 0df8864ae0604418014bd61b84eeffd085a7a4d9 Mon Sep 17 00:00:00 2001 From: Ilya Fedin Date: Fri, 8 Mar 2024 12:25:13 +0400 Subject: [PATCH] Port specific_linux to cppgir --- Telegram/CMakeLists.txt | 3 + .../platform/linux/specific_linux.cpp | 407 ++++++++++-------- 2 files changed, 224 insertions(+), 186 deletions(-) diff --git a/Telegram/CMakeLists.txt b/Telegram/CMakeLists.txt index 76e06c8e1..9285d5ad2 100644 --- a/Telegram/CMakeLists.txt +++ b/Telegram/CMakeLists.txt @@ -1679,6 +1679,9 @@ else() desktop-app::external_glibmm ) + include(${cmake_helpers_loc}/external/glib/generate_dbus.cmake) + generate_dbus(Telegram org.freedesktop.portal. XdpBackground ${third_party_loc}/xdg-desktop-portal/data/org.freedesktop.portal.Background.xml) + if (NOT DESKTOP_APP_DISABLE_X11_INTEGRATION) target_link_libraries(Telegram PRIVATE diff --git a/Telegram/SourceFiles/platform/linux/specific_linux.cpp b/Telegram/SourceFiles/platform/linux/specific_linux.cpp index c0cbed82e..c892885d0 100644 --- a/Telegram/SourceFiles/platform/linux/specific_linux.cpp +++ b/Telegram/SourceFiles/platform/linux/specific_linux.cpp @@ -38,6 +38,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include #include +#include +#include +#include + #include #include #include @@ -48,12 +52,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include +namespace { + +using namespace gi::repository; +namespace Gio = gi::repository::Gio; using namespace Platform; using Platform::internal::WaylandIntegration; -namespace Platform { -namespace { - void PortalAutostart(bool enabled, Fn done) { if (cExeName().isEmpty()) { if (done) { @@ -62,127 +67,141 @@ void PortalAutostart(bool enabled, Fn done) { return; } - const auto connection = [&] { - try { - return Gio::DBus::Connection::get_sync( - Gio::DBus::BusType::SESSION); - } catch (const std::exception &e) { - if (done) { - LOG(("Portal Autostart Error: %1").arg(e.what())); + 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) { + LOG(("Portal Autostart Error: %1").arg( + proxy.error().what())); + done(false); + } + return; } - return Glib::RefPtr(); - } - }(); - if (!connection) { - if (done) { - done(false); - } - return; - } + auto interface = XdpBackground::Background(*proxy); - const auto handleToken = Glib::ustring("tdesktop") - + std::to_string(base::RandomValue()); + const auto handleToken = "tdesktop" + + std::to_string(base::RandomValue()); - std::vector commandline; - commandline.push_back(cExeName().toStdString()); - if (Core::Launcher::Instance().customWorkingDir()) { - commandline.push_back("-workdir"); - commandline.push_back(cWorkingDir().toStdString()); - } - commandline.push_back("-autostart"); + auto uniqueName = std::string( + proxy->get_connection().get_unique_name()); + uniqueName.erase(0, 1); + uniqueName.replace(uniqueName.find('.'), 1, 1, '_'); - std::map options; - options["handle_token"] = Glib::create_variant(handleToken); - options["reason"] = Glib::create_variant( - Glib::ustring( - tr::lng_settings_auto_start(tr::now).toStdString())); - options["autostart"] = Glib::create_variant(enabled); - options["commandline"] = Glib::create_variant(commandline); - options["dbus-activatable"] = Glib::create_variant(false); + const auto window = std::make_shared(); + window->setAttribute(Qt::WA_DontShowOnScreen); + window->setWindowModality(Qt::ApplicationModal); + window->show(); - auto uniqueName = connection->get_unique_name(); - uniqueName.erase(0, 1); - uniqueName.replace(uniqueName.find('.'), 1, 1, '_'); + 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); - const auto requestPath = base::Platform::XDP::kObjectPath - + Glib::ustring("/request/") - + uniqueName - + '/' - + handleToken; - - const auto window = std::make_shared(); - window->setAttribute(Qt::WA_DontShowOnScreen); - window->setWindowModality(Qt::ApplicationModal); - window->show(); - - const auto signalId = std::make_shared(); - *signalId = connection->signal_subscribe( - [=]( - const Glib::RefPtr &connection, - const Glib::ustring &sender_name, - const Glib::ustring &object_path, - const Glib::ustring &interface_name, - const Glib::ustring &signal_name, - const Glib::VariantContainerBase ¶meters) { - Core::Sandbox::Instance().customEnterFromEventLoop([&] { - (void)window; // don't destroy until finish - - try { - const auto response = parameters.get_child( - 0 - ).get_dynamic(); - - if (response) { + if (!requestProxy) { if (done) { - LOG(("Portal Autostart Error: Request denied")); + LOG(("Portal Autostart Error: %1").arg( + requestProxy.error().what())); done(false); } - } else if (done) { - done(enabled); - } - } catch (const std::exception &e) { - if (done) { - LOG(("Portal Autostart Error: %1").arg(e.what())); - done(false); - } - } - - if (*signalId) { - connection->signal_unsubscribe(*signalId); - } - }); - }, - base::Platform::XDP::kService, - base::Platform::XDP::kRequestInterface, - "Response", - requestPath); - - connection->call( - base::Platform::XDP::kObjectPath, - "org.freedesktop.portal.Background", - "RequestBackground", - Glib::create_variant(std::tuple{ - base::Platform::XDP::ParentWindowID(), - options, - }), - [=](const Glib::RefPtr &result) { - Core::Sandbox::Instance().customEnterFromEventLoop([&] { - try { - connection->call_finish(result); - } catch (const std::exception &e) { - if (done) { - LOG(("Portal Autostart Error: %1").arg(e.what())); - done(false); + return; } - if (*signalId) { - connection->signal_unsubscribe(*signalId); + auto request = XdpRequest::Request(*requestProxy); + const auto signalId = std::make_shared(); + *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 commandline; + commandline.push_back(cExeName().toStdString()); + if (Core::Launcher::Instance().customWorkingDir()) { + commandline.push_back("-workdir"); + commandline.push_back(cWorkingDir().toStdString()); } - } - }); - }, - base::Platform::XDP::kService); + commandline.push_back("-autostart"); + + interface.call_request_background( + std::string(base::Platform::XDP::ParentWindowID()), + 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) { + LOG(("Portal Autostart Error: %1") + .arg(result.error().what())); + done(false); + } + + request.disconnect(*signalId); + } + }); + }); + }); + }); } bool GenerateDesktopFile( @@ -218,77 +237,89 @@ bool GenerateDesktopFile( return false; } - try { - const auto target = Glib::KeyFile::create(); - target->load_from_data( - sourceText, - Glib::KeyFile::Flags::KEEP_COMMENTS - | Glib::KeyFile::Flags::KEEP_TRANSLATIONS); + 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().what())); + } + return false; + } - for (const auto &group : target->get_groups()) { - if (onlyMainGroup && group != "Desktop Entry") { - target->remove_group(group); - continue; + 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().what())); + } + return false; } + continue; + } - if (target->has_key(group, "TryExec")) { - target->set_string( + 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, - "TryExec", - KShell::joinArgs({ executable }).replace( + "Exec", + KShell::joinArgs(exec).replace( '\\', qstr("\\\\")).toStdString()); - } + } else { + auto exec = KShell::splitArgs( + QString::fromStdString( + target.get_string(group, "Exec", nullptr) + ).replace( + qstr("\\\\"), + qstr("\\"))); - if (target->has_key(group, "Exec")) { - if (group == "Desktop Entry" && !args.isEmpty()) { - QStringList exec; - exec.append(executable); + if (!exec.isEmpty()) { + exec[0] = executable; if (Core::Launcher::Instance().customWorkingDir()) { - exec.append(u"-workdir"_q); - exec.append(cWorkingDir()); + exec.insert(1, u"-workdir"_q); + exec.insert(2, cWorkingDir()); } - exec.append(args); - target->set_string( + target.set_string( group, "Exec", KShell::joinArgs(exec).replace( '\\', qstr("\\\\")).toStdString()); - } else { - auto exec = KShell::splitArgs( - QString::fromStdString( - target->get_string(group, "Exec") - ).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->has_key("Desktop Entry", "DBusActivatable")) { - target->remove_key("Desktop Entry", "DBusActivatable"); - } + if (!args.isEmpty()) { + target.remove_key("Desktop Entry", "DBusActivatable"); + } - target->save_to_file(targetFile.toStdString()); - } catch (const std::exception &e) { + const auto saved = target.save_to_file(targetFile.toStdString()); + if (!saved) { if (!silent) { - LOG(("App Error: %1").arg(e.what())); + LOG(("App Error: %1").arg(saved.error().what())); } return false; } @@ -357,10 +388,10 @@ bool GenerateServiceFile(bool silent = false) { DEBUG_LOG(("App Info: placing D-Bus service file to %1").arg(targetPath)); if (!QDir(targetPath).exists()) QDir().mkpath(targetPath); - const auto target = Glib::KeyFile::create(); + auto target = GLib::KeyFile::new_(); constexpr auto group = "D-BUS Service"; - target->set_string( + target.set_string( group, "Name", QGuiApplication::desktopFileName().toStdString()); @@ -371,21 +402,21 @@ bool GenerateServiceFile(bool silent = false) { exec.append(u"-workdir"_q); exec.append(cWorkingDir()); } - target->set_string( + target.set_string( group, "Exec", KShell::joinArgs(exec).toStdString()); - try { - target->save_to_file(targetFile.toStdString()); - } catch (const std::exception &e) { + const auto saved = target.save_to_file(targetFile.toStdString()); + if (!saved) { if (!silent) { - LOG(("App Error: %1").arg(e.what())); + LOG(("App Error: %1").arg(saved.error().what())); } return false; } - if (!Core::UpdaterDisabled() && !Core::Launcher::Instance().customWorkingDir()) { + if (!Core::UpdaterDisabled() + && !Core::Launcher::Instance().customWorkingDir()) { DEBUG_LOG(("App Info: removing old D-Bus service files")); char md5Hash[33] = { 0 }; @@ -397,19 +428,21 @@ bool GenerateServiceFile(bool silent = false) { md5Hash)); } - try { - Gio::DBus::Connection::get_sync( - Gio::DBus::BusType::SESSION - )->call( - base::Platform::DBus::kObjectPath, - base::Platform::DBus::kInterface, - "ReloadConfig", - {}, - {}, - base::Platform::DBus::kService - ); - } catch (...) { - } + 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; } @@ -447,6 +480,8 @@ void InstallLauncher() { } // namespace +namespace Platform { + void SetApplicationIcon(const QIcon &icon) { QApplication::setWindowIcon(icon); } @@ -648,11 +683,11 @@ void start() { qputenv("PULSE_PROP_application.name", AppName.utf8()); qputenv("PULSE_PROP_application.icon_name", base::IconName().toLatin1()); - Glib::set_prgname(cExeName().toStdString()); - Glib::set_application_name(AppName.data()); + GLib::set_prgname(cExeName().toStdString()); + GLib::set_application_name(AppName.data()); Glib::init(); - Gio::init(); + ::Gio::init(); Webview::WebKitGTK::SetSocketPath(u"%1/%2-%3-webview-%4"_q.arg( QDir::tempPath(),