From 345b2cb835f47fdae1e1ee2e34fdc4d1a111dd53 Mon Sep 17 00:00:00 2001 From: Ilya Fedin Date: Mon, 3 Mar 2025 18:12:36 +0000 Subject: [PATCH] Move notification closing to NotificationData destruction --- .../linux/notifications_manager_linux.cpp | 148 +++++------------- 1 file changed, 38 insertions(+), 110 deletions(-) diff --git a/Telegram/SourceFiles/platform/linux/notifications_manager_linux.cpp b/Telegram/SourceFiles/platform/linux/notifications_manager_linux.cpp index 4cf1f82e2..b1fb8327e 100644 --- a/Telegram/SourceFiles/platform/linux/notifications_manager_linux.cpp +++ b/Telegram/SourceFiles/platform/linux/notifications_manager_linux.cpp @@ -158,25 +158,21 @@ public: void clearNotification(NotificationId id); void invokeIfNotInhibited(Fn callback); - ~Private(); - private: struct NotificationData : public base::has_weak_ptr { - uint id = 0; + std::variant id; + rpl::lifetime lifetime; }; using Notification = std::unique_ptr; const not_null _manager; - - base::flat_map< - ContextId, - base::flat_map>> _notifications; - Gio::Application _application; XdgNotifications::NotificationsProxy _proxy; XdgNotifications::Notifications _interface; Media::Audio::LocalDiskCache _sounds; + base::flat_map< + ContextId, + base::flat_map> _notifications; rpl::lifetime _lifetime; }; @@ -427,7 +423,7 @@ void Manager::Private::init(XdgNotifications::NotificationsProxy proxy) { Core::Sandbox::Instance().customEnterFromEventLoop([&] { for (const auto &[key, notifications] : _notifications) { for (const auto &[msgId, notification] : notifications) { - if (id == v::get(notification)->id) { + if (id == v::get(notification->id)) { if (actionName == "default") { _manager->notificationActivated({ key, msgId }); } else if (actionName == "mail-mark-read") { @@ -451,7 +447,7 @@ void Manager::Private::init(XdgNotifications::NotificationsProxy proxy) { Core::Sandbox::Instance().customEnterFromEventLoop([&] { for (const auto &[key, notifications] : _notifications) { for (const auto &[msgId, notification] : notifications) { - if (id == v::get(notification)->id) { + if (id == v::get(notification->id)) { _manager->notificationReplied( { key, msgId }, { QString::fromStdString(text), {} }); @@ -472,7 +468,7 @@ void Manager::Private::init(XdgNotifications::NotificationsProxy proxy) { std::string token) { for (const auto &[key, notifications] : _notifications) { for (const auto &[msgId, notification] : notifications) { - if (id == v::get(notification)->id) { + if (id == v::get(notification->id)) { GLib::setenv("XDG_ACTIVATION_TOKEN", token, true); return; } @@ -505,8 +501,7 @@ void Manager::Private::init(XdgNotifications::NotificationsProxy proxy) { * In all other cases we keep the notification reference so that we may clear the notification later from history, * if the message for that notification is read (e.g. chat is opened or read from another device). */ - if (id == v::get(notification)->id - && reason == 2) { + if (id == v::get(notification->id) && reason == 2) { clearNotification({ key, msgId }); return; } @@ -535,18 +530,16 @@ void Manager::Private::showNotification( .msgId = info.itemId, }; auto notification = _application - ? std::variant( - Gio::Notification::new_( - info.subtitle.isEmpty() - ? info.title.toStdString() - : info.subtitle.toStdString() - + " (" + info.title.toStdString() + ')')) - : std::variant( - std::make_unique()); + ? Gio::Notification::new_( + info.subtitle.isEmpty() + ? info.title.toStdString() + : info.subtitle.toStdString() + + " (" + info.title.toStdString() + ')') + : Gio::Notification(); std::vector actions; auto hints = GLib::VariantDict::new_(); - v::match(notification, [&](Gio::Notification ¬ification) { + if (notification) { notification.set_body(info.message.toStdString()); notification.set_icon( @@ -601,7 +594,7 @@ void Manager::Private::showNotification( "app.notification-mark-as-read", notificationVariant); } - }, [&](const Notification ¬ification) { + } else { if (HasCapability("actions")) { actions.push_back("default"); actions.push_back(tr::lng_open_link(tr::now).toStdString()); @@ -661,11 +654,11 @@ void Manager::Private::showNotification( hints.insert_value("desktop-entry", GLib::Variant::new_string( QGuiApplication::desktopFileName().toStdString())); - }); + } const auto imageKey = GetImageKey(); if (!options.hideNameAndPhoto) { - v::match(notification, [&](Gio::Notification ¬ification) { + if (notification) { QByteArray imageData; QBuffer buffer(&imageData); buffer.open(QIODevice::WriteOnly); @@ -679,11 +672,7 @@ void Manager::Private::showNotification( reinterpret_cast(imageData.constData()), imageData.size(), [imageData] {}))); - }, [&](const Notification ¬ification) { - if (imageKey.empty()) { - return; - } - + } else if (!imageKey.empty()) { const auto image = Window::Notifications::GenerateUserpic( peer, userpicView @@ -703,43 +692,27 @@ void Manager::Private::showNotification( true, [image] {}), })); - }); - } - - auto i = _notifications.find(key); - if (i != end(_notifications)) { - auto j = i->second.find(info.itemId); - if (j != end(i->second)) { - auto oldNotification = std::move(j->second); - i->second.erase(j); - v::match(oldNotification, [&]( - const std::string &oldNotification) { - _application.withdraw_notification(oldNotification); - }, [&](const Notification &oldNotification) { - _interface.call_close_notification( - oldNotification->id, - nullptr); - }); } - } else { - i = _notifications.emplace(key).first; } - v::match(notification, [&](Gio::Notification ¬ification) { - const auto j = i->second.emplace( - info.itemId, - Gio::dbus_generate_guid()).first; - _application.send_notification( - v::get(j->second), - notification); - }, [&](Notification ¬ification) { - const auto j = i->second.emplace( - info.itemId, - std::move(notification)).first; - const auto weak = base::make_weak( - v::get(j->second).get()); + const auto &data + = _notifications[key][info.itemId] + = std::make_unique(); + data->lifetime.add([=, notification = data.get()] { + v::match(notification->id, [&](const std::string &id) { + _application.withdraw_notification(id); + }, [&](uint id) { + _interface.call_close_notification(id, nullptr); + }, [](v::null_t) {}); + }); + if (notification) { + const auto id = Gio::dbus_generate_guid(); + data->id = id; + _application.send_notification(id, notification); + } else { // work around snap's activation restriction + const auto weak = base::make_weak(data); StartServiceAsync( _proxy.get_connection(), crl::guard(weak, [=]() mutable { @@ -808,19 +781,11 @@ void Manager::Private::showNotification( &callbackWrap->wrapper, callbackWrap); })); - }); + } } void Manager::Private::clearAll() { - for (const auto &[key, notifications] : base::take(_notifications)) { - for (const auto &[msgId, notification] : notifications) { - v::match(notification, [&](const std::string ¬ification) { - _application.withdraw_notification(notification); - }, [&](const Notification ¬ification) { - _interface.call_close_notification(notification->id, nullptr); - }); - } - } + _notifications.clear(); } void Manager::Private::clearFromItem(not_null item) { @@ -837,16 +802,10 @@ void Manager::Private::clearFromItem(not_null item) { if (j == i->second.end()) { return; } - const auto taken = base::take(j->second); i->second.erase(j); if (i->second.empty()) { _notifications.erase(i); } - v::match(taken, [&](const std::string &taken) { - _application.withdraw_notification(taken); - }, [&](const Notification &taken) { - _interface.call_close_notification(taken->id, nullptr); - }); } void Manager::Private::clearFromTopic(not_null topic) { @@ -856,16 +815,7 @@ void Manager::Private::clearFromTopic(not_null topic) { }; const auto i = _notifications.find(key); if (i != _notifications.cend()) { - const auto temp = base::take(i->second); _notifications.erase(i); - - for (const auto &[msgId, notification] : temp) { - v::match(notification, [&](const std::string ¬ification) { - _application.withdraw_notification(notification); - }, [&](const Notification ¬ification) { - _interface.call_close_notification(notification->id, nullptr); - }); - } } } @@ -879,16 +829,7 @@ void Manager::Private::clearFromHistory(not_null history) { while (i != _notifications.cend() && i->first.sessionId == sessionId && i->first.peerId == peerId) { - const auto temp = base::take(i->second); i = _notifications.erase(i); - - for (const auto &[msgId, notification] : temp) { - v::match(notification, [&](const std::string ¬ification) { - _application.withdraw_notification(notification); - }, [&](const Notification ¬ification) { - _interface.call_close_notification(notification->id, nullptr); - }); - } } } @@ -898,16 +839,7 @@ void Manager::Private::clearFromSession(not_null session) { .sessionId = sessionId, }); while (i != _notifications.cend() && i->first.sessionId == sessionId) { - const auto temp = base::take(i->second); i = _notifications.erase(i); - - for (const auto &[msgId, notification] : temp) { - v::match(notification, [&](const std::string ¬ification) { - _application.withdraw_notification(notification); - }, [&](const Notification ¬ification) { - _interface.call_close_notification(notification->id, nullptr); - }); - } } } @@ -926,10 +858,6 @@ void Manager::Private::invokeIfNotInhibited(Fn callback) { } } -Manager::Private::~Private() { - clearAll(); -} - Manager::Manager(not_null system) : NativeManager(system) , _private(std::make_unique(this)) {