From 8669e6a89164d99212036577c81a7d988741dac5 Mon Sep 17 00:00:00 2001 From: Ilya Fedin Date: Fri, 4 Aug 2023 04:05:35 +0400 Subject: [PATCH] Port GApplication to cppgir --- .../platform/linux/integration_linux.cpp | 311 +++++++++--------- .../window/notifications_manager.cpp | 13 +- 2 files changed, 156 insertions(+), 168 deletions(-) diff --git a/Telegram/SourceFiles/platform/linux/integration_linux.cpp b/Telegram/SourceFiles/platform/linux/integration_linux.cpp index a465ddefe..5f22f596e 100644 --- a/Telegram/SourceFiles/platform/linux/integration_linux.cpp +++ b/Telegram/SourceFiles/platform/linux/integration_linux.cpp @@ -17,79 +17,177 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include +#include +#include #include -#include -typedef GApplication TDesktopApplication; -typedef GApplicationClass TDesktopApplicationClass; +namespace Platform { +namespace { -G_DEFINE_TYPE( - TDesktopApplication, - t_desktop_application, - G_TYPE_APPLICATION) +using namespace gi::repository; -static void t_desktop_application_class_init( - TDesktopApplicationClass *klass) { - const auto application_class = G_APPLICATION_CLASS(klass); +class Application : public Gio::impl::ApplicationImpl { +public: + Application(); - 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) { + void before_emit_(GLib::Variant platformData) noexcept override { 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); + if (auto token = platformData.lookup_value(key)) { + qputenv( + "XDG_ACTIVATION_TOKEN", + token.get_string(nullptr).c_str()); break; } } } - }; + } - application_class->add_platform_data = []( - GApplication *application, - GVariantBuilder *builder) { + void startup_() noexcept override { + // GNotification + InvokeQueued(qApp, [] { + Core::App().notifications().createManager(); + }); + + Gio::impl::ApplicationImpl::startup_(); + QEventLoop().exec(); + quit(); + } + + void activate_() noexcept override { + Core::Sandbox::Instance().customEnterFromEventLoop([] { + Core::App().activate(); + }); + } + + void open_(GFile **files, int n_files, const char*) noexcept override { + Core::Sandbox::Instance().customEnterFromEventLoop([&] { + for (int i = 0; i < n_files; ++i) { + QFileOpenEvent e( + QUrl(QString::fromUtf8(g_file_get_uri(files[i])))); + QGuiApplication::sendEvent(qApp, &e); + } + }); + } + + int command_line_(Gio::ApplicationCommandLine) noexcept override { + return 0; + } + + gboolean local_command_line_(char***, int*) noexcept override { + return false; + } + + void add_platform_data_(GLib::VariantBuilder builder) noexcept override { 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())); + builder.add_value( + GLib::Variant::new_dict_entry( + GLib::Variant::new_string("activation-token"), + GLib::Variant::new_variant( + GLib::Variant::new_string(token.toStdString())))); qunsetenv("XDG_ACTIVATION_TOKEN"); } } - }; + } +}; + +Application::Application() +: Gio::impl::ApplicationImpl(this) { + const auto appId = QGuiApplication::desktopFileName().toStdString(); + if (Gio::Application::id_is_valid(appId)) { + set_application_id(appId); + } + set_flags(Gio::ApplicationFlags::HANDLES_OPEN_); + + auto actionMap = Gio::ActionMap(*this); + + auto quitAction = Gio::SimpleAction::new_("quit"); + quitAction.signal_activate().connect([]( + Gio::SimpleAction, + GLib::Variant parameter) { + Core::Sandbox::Instance().customEnterFromEventLoop([] { + Core::Quit(); + }); + }); + actionMap.add_action(quitAction); + + using Window::Notifications::Manager; + using NotificationId = Manager::NotificationId; + using NotificationIdTuple = std::invoke_result_t< + decltype(&NotificationId::toTuple), + NotificationId* + >; + + const auto notificationIdVariantType = [] { + try { + return gi::wrap( + Glib::create_variant( + NotificationId().toTuple() + ).get_type().gobj_copy(), + gi::transfer_full, + gi::direction_out + ); + } catch (...) { + return GLib::VariantType(); + } + }(); + + auto notificationActivateAction = Gio::SimpleAction::new_( + "notification-activate", + notificationIdVariantType); + + notificationActivateAction.signal_activate().connect([]( + Gio::SimpleAction, + GLib::Variant parameter) { + Core::Sandbox::Instance().customEnterFromEventLoop([&] { + try { + const auto &app = Core::App(); + app.notifications().manager().notificationActivated( + NotificationId::FromTuple( + Glib::wrap( + parameter.gobj_copy_() + ).get_dynamic() + ) + ); + } catch (...) { + } + }); + }); + + actionMap.add_action(notificationActivateAction); + + auto notificationMarkAsReadAction = Gio::SimpleAction::new_( + "notification-mark-as-read", + notificationIdVariantType); + + notificationMarkAsReadAction.signal_activate().connect([]( + Gio::SimpleAction, + GLib::Variant parameter) { + Core::Sandbox::Instance().customEnterFromEventLoop([&] { + try { + const auto &app = Core::App(); + app.notifications().manager().notificationReplied( + NotificationId::FromTuple( + Glib::wrap( + parameter.gobj_copy_() + ).get_dynamic() + ), + {} + ); + } catch (...) { + } + }); + }); + + actionMap.add_action(notificationMarkAsReadAction); } -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(); @@ -103,8 +201,6 @@ private: void initInhibit(); - static void LaunchNativeApplication(); - XdpInhibit::InhibitProxy _inhibitProxy; base::Platform::XDP::SettingWatcher _darkModeWatcher; }; @@ -146,8 +242,8 @@ LinuxIntegration::LinuxIntegration() void LinuxIntegration::init() { initInhibit(); - Glib::signal_idle().connect_once([] { - LaunchNativeApplication(); + GLib::idle_add_once([] { + gi::make_ref()->run(0, nullptr); }); } @@ -207,115 +303,6 @@ void LinuxIntegration::initInhibit() { nullptr); } -void LinuxIntegration::LaunchNativeApplication() { - const auto appId = QGuiApplication::desktopFileName().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([weak = std::weak_ptr(app)] { - const auto app = weak.lock(); - if (!app) { - return; - } - - // 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 Glib::create_variant( - NotificationId().toTuple() - ).get_type(); - } catch (...) { - return Glib::VariantType(); - } - }(); - - app->add_action_with_parameter( - "notification-activate", - notificationIdVariantType, - [](const Glib::VariantBase ¶meter) { - Core::Sandbox::Instance().customEnterFromEventLoop([&] { - try { - const auto &app = Core::App(); - app.notifications().manager().notificationActivated( - NotificationId::FromTuple( - parameter.get_dynamic() - ) - ); - } catch (...) { - } - }); - }); - - app->add_action_with_parameter( - "notification-mark-as-read", - notificationIdVariantType, - [](const Glib::VariantBase ¶meter) { - Core::Sandbox::Instance().customEnterFromEventLoop([&] { - try { - const auto &app = Core::App(); - app.notifications().manager().notificationReplied( - NotificationId::FromTuple( - parameter.get_dynamic() - ), - {} - ); - } catch (...) { - } - }); - }); - - app->run(0, nullptr); -} - } // namespace std::unique_ptr CreateIntegration() { diff --git a/Telegram/SourceFiles/window/notifications_manager.cpp b/Telegram/SourceFiles/window/notifications_manager.cpp index 2049d28d1..5a52f4480 100644 --- a/Telegram/SourceFiles/window/notifications_manager.cpp +++ b/Telegram/SourceFiles/window/notifications_manager.cpp @@ -40,9 +40,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include -#if __has_include() -#include -#endif // __has_include() +#if __has_include() +#include +#endif // __has_include() namespace Window { namespace Notifications { @@ -90,11 +90,12 @@ base::options::toggle OptionGNotification({ .description = "Force enable GLib's GNotification." " When disabled, autodetect is used.", .scope = [] { -#if __has_include() +#if __has_include() + using namespace gi::repository; return bool(Gio::Application::get_default()); -#else // __has_include() +#else // __has_include() return false; -#endif // __has_include() +#endif // __has_include() }, .restartRequired = true, });