diff --git a/Telegram/SourceFiles/platform/linux/integration_linux.cpp b/Telegram/SourceFiles/platform/linux/integration_linux.cpp index a465ddefeea66..61248cc95df8f 100644 --- a/Telegram/SourceFiles/platform/linux/integration_linux.cpp +++ b/Telegram/SourceFiles/platform/linux/integration_linux.cpp @@ -17,78 +17,167 @@ For license and copyright information please follow this link: #include +#include +#include #include -#include -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); +namespace Platform { +namespace { - application_class->local_command_line = []( - GApplication *application, - char ***arguments, - int *exit_status) -> gboolean { - return false; - }; +using namespace gi::repository; - application_class->command_line = []( - GApplication *application, - GApplicationCommandLine *cmdline) { - return 0; - }; +class Application : public Gio::impl::ApplicationImpl { +public: + Application(); - 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; } } } - }; + } + + void activate_() noexcept override { + Core::Sandbox::Instance().customEnterFromEventLoop([] { + Core::App().activate(); + }); + } - application_class->add_platform_data = []( - GApplication *application, - GVariantBuilder *builder) { + 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); + } + }); + } + + 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"); } } - }; -} + } +}; -static void t_desktop_application_init(TDesktopApplication *application) { -} +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_); -namespace Platform { -namespace { + auto actionMap = Gio::ActionMap(*this); -using namespace gi::repository; -namespace Gio = gi::repository::Gio; + 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); +} + +gi::ref_ptr MakeApplication() { + const auto result = gi::make_ref(); + if (const auto registered = result->register_(); !registered) { + LOG(("App Error: Failed to register: %1").arg( + QString::fromStdString(registered.error().message_()))); + return nullptr; + } + return result; +} class LinuxIntegration final : public Integration { public: @@ -103,14 +192,14 @@ class LinuxIntegration final : public Integration { void initInhibit(); - static void LaunchNativeApplication(); - + const gi::ref_ptr _application; XdpInhibit::InhibitProxy _inhibitProxy; base::Platform::XDP::SettingWatcher _darkModeWatcher; }; LinuxIntegration::LinuxIntegration() -: _inhibitProxy( +: _application(MakeApplication()) +, _inhibitProxy( XdpInhibit::InhibitProxy::new_for_bus_sync( Gio::BusType::SESSION_, Gio::DBusProxyFlags::DO_NOT_AUTO_START_AT_CONSTRUCTION_, @@ -139,16 +228,12 @@ LinuxIntegration::LinuxIntegration() if (!QCoreApplication::eventDispatcher()->inherits( "QEventDispatcherGlib")) { g_warning("Qt is running without GLib event loop integration, " - "except various functionality to not to work."); + "expect various functionality to not to work."); } } void LinuxIntegration::init() { initInhibit(); - - Glib::signal_idle().connect_once([] { - LaunchNativeApplication(); - }); } void LinuxIntegration::initInhibit() { @@ -207,115 +292,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 2049d28d1ae39..5a52f44809677 100644 --- a/Telegram/SourceFiles/window/notifications_manager.cpp +++ b/Telegram/SourceFiles/window/notifications_manager.cpp @@ -40,9 +40,9 @@ For license and copyright information please follow this link: #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, }); diff --git a/Telegram/lib_base b/Telegram/lib_base index 609a9e69f2a69..1726a4fda092f 160000 --- a/Telegram/lib_base +++ b/Telegram/lib_base @@ -1 +1 @@ -Subproject commit 609a9e69f2a69fea050e75cbe2b546b4aa1e4914 +Subproject commit 1726a4fda092f910928f0e29eac358fc546d54a5 diff --git a/cmake b/cmake index d1c98b4c472c7..002093a8d0133 160000 --- a/cmake +++ b/cmake @@ -1 +1 @@ -Subproject commit d1c98b4c472c7b59c239006a06d7a784a60a347f +Subproject commit 002093a8d0133f33758a8e559f53bef21175209b