diff --git a/Telegram/SourceFiles/platform/linux/linux_notification_service_watcher.cpp b/Telegram/SourceFiles/platform/linux/linux_notification_service_watcher.cpp index 1aa0fb969..3198eed94 100644 --- a/Telegram/SourceFiles/platform/linux/linux_notification_service_watcher.cpp +++ b/Telegram/SourceFiles/platform/linux/linux_notification_service_watcher.cpp @@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "core/application.h" #include "main/main_domain.h" #include "window/notifications_manager.h" +#include "platform/linux/specific_linux.h" #include @@ -22,10 +23,16 @@ NotificationServiceWatcher::NotificationServiceWatcher() QDBusConnection::sessionBus(), QDBusServiceWatcher::WatchForOwnerChange) { const auto signal = &QDBusServiceWatcher::serviceOwnerChanged; - QObject::connect(&_dbusWatcher, signal, [=] { + QObject::connect(&_dbusWatcher, signal, [=]( + const QString &service, + const QString &oldOwner, + const QString &newOwner) { crl::on_main([=] { if (!Core::App().domain().started()) { return; + } else if (IsNotificationServiceActivatable() + && newOwner.isEmpty()) { + return; } Core::App().notifications().createManager(); diff --git a/Telegram/SourceFiles/platform/linux/notifications_manager_linux.cpp b/Telegram/SourceFiles/platform/linux/notifications_manager_linux.cpp index 1637aff50..57775dba2 100644 --- a/Telegram/SourceFiles/platform/linux/notifications_manager_linux.cpp +++ b/Telegram/SourceFiles/platform/linux/notifications_manager_linux.cpp @@ -21,6 +21,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include #include #include +#include +#include #include #include #include @@ -64,7 +66,7 @@ bool GetServiceRegistered() { : activatable; } -std::optional GetServerInformation() { +void GetServerInformation(Fn)> callback) { using ServerInformationReply = QDBusPendingReply< QString, QString, @@ -77,59 +79,63 @@ std::optional GetServerInformation() { kInterface.utf16(), qsl("GetServerInformation")); - // We may be launched earlier than notification daemon - while (true) { - ServerInformationReply reply = QDBusConnection::sessionBus() - .asyncCall(message); + const auto async = QDBusConnection::sessionBus().asyncCall(message); + auto watcher = new QDBusPendingCallWatcher(async); - reply.waitForFinished(); + const auto finished = [=](QDBusPendingCallWatcher *call) { + const ServerInformationReply reply = *call; if (reply.isValid()) { - return { - reply.argumentAt<0>(), - reply.argumentAt<1>(), - QVersionNumber::fromString(reply.argumentAt<2>()), - QVersionNumber::fromString(reply.argumentAt<3>()), - }; + crl::on_main([=] { + callback(ServerInformation{ + reply.argumentAt<0>(), + reply.argumentAt<1>(), + QVersionNumber::fromString(reply.argumentAt<2>()), + QVersionNumber::fromString(reply.argumentAt<3>()), + }); + }); + } else { + LOG(("Native notification error: %1").arg( + reply.error().message())); + + crl::on_main([=] { callback(std::nullopt); }); } - LOG(("Native notification error: %1").arg(reply.error().message())); + call->deleteLater(); + }; - if (reply.error().type() != QDBusError::NoReply) { - break; - } - } - - return std::nullopt; + QObject::connect(watcher, &QDBusPendingCallWatcher::finished, finished); } -QStringList GetCapabilities() { +void GetCapabilities(Fn callback) { const auto message = QDBusMessage::createMethodCall( kService.utf16(), kObjectPath.utf16(), kInterface.utf16(), qsl("GetCapabilities")); - // We may be launched earlier than notification daemon - while (true) { - const QDBusReply reply = QDBusConnection::sessionBus() - .call(message); + const auto async = QDBusConnection::sessionBus().asyncCall(message); + auto watcher = new QDBusPendingCallWatcher(async); + + const auto finished = [=](QDBusPendingCallWatcher *call) { + const QDBusPendingReply reply = *call; if (reply.isValid()) { - return reply.value(); + crl::on_main([=] { callback(reply.value()); }); + } else { + LOG(("Native notification error: %1").arg( + reply.error().message())); + + crl::on_main([=] { callback({}); }); } - LOG(("Native notification error: %1").arg(reply.error().message())); + call->deleteLater(); + }; - if (reply.error().type() != QDBusError::NoReply) { - break; - } - } - - return {}; + QObject::connect(watcher, &QDBusPendingCallWatcher::finished, finished); } -bool GetInhibitionSupported() { +void GetInhibitionSupported(Fn callback) { auto message = QDBusMessage::createMethodCall( kService.utf16(), kObjectPath.utf16(), @@ -141,24 +147,21 @@ bool GetInhibitionSupported() { qsl("Inhibited") }); - // We may be launched earlier than notification daemon - while (true) { - const QDBusError error = QDBusConnection::sessionBus().call(message); + const auto async = QDBusConnection::sessionBus().asyncCall(message); + auto watcher = new QDBusPendingCallWatcher(async); - if (!error.isValid()) { - return true; - } else if (error.type() == QDBusError::InvalidArgs) { - break; + const auto finished = [=](QDBusPendingCallWatcher *call) { + const auto error = QDBusPendingReply(*call).error(); + + if (error.isValid() && error.type() != QDBusError::InvalidArgs) { + LOG(("Native notification error: %1").arg(error.message())); } - LOG(("Native notification error: %1").arg(error.message())); + crl::on_main([=] { callback(!error.isValid()); }); + call->deleteLater(); + }; - if (error.type() != QDBusError::NoReply) { - break; - } - } - - return false; + QObject::connect(watcher, &QDBusPendingCallWatcher::finished, finished); } bool Inhibited() { @@ -681,26 +684,56 @@ bool Enforced() { return IsQualifiedDaemon() || IsWayland(); } -std::unique_ptr Create( - Window::Notifications::System *system) { +void Create(Window::Notifications::System *system) { ServiceRegistered = GetServiceRegistered(); - if (Supported()) { - CurrentServerInformation = GetServerInformation(); - CurrentCapabilities = GetCapabilities(); - InhibitionSupported = GetInhibitionSupported(); + const auto managerSetter = [=] { + using ManagerType = Window::Notifications::ManagerType; + if ((Core::App().settings().nativeNotifications() && Supported()) + || Enforced()) { + if (*system->managerType() != ManagerType::Native) { + system->setManager(std::make_unique(system)); + } + } else { + if (*system->managerType() != ManagerType::Default) { + system->setManager(nullptr); + } + } + }; + + if (!system->managerType().has_value()) { + using DummyManager = Window::Notifications::DummyManager; + system->setManager(std::make_unique(system)); + } + + if (ServiceRegistered) { + const auto counter = std::make_shared(3); + const auto oneReady = [=] { + if (!--*counter) { + managerSetter(); + } + }; + + GetServerInformation([=](std::optional result) { + CurrentServerInformation = result; + oneReady(); + }); + + GetCapabilities([=](QStringList result) { + CurrentCapabilities = result; + oneReady(); + }); + + GetInhibitionSupported([=](bool result) { + InhibitionSupported = result; + oneReady(); + }); } else { CurrentServerInformation = std::nullopt; CurrentCapabilities = QStringList{}; InhibitionSupported = false; + managerSetter(); } - - if ((Core::App().settings().nativeNotifications() && Supported()) - || Enforced()) { - return std::make_unique(system); - } - - return nullptr; } class Manager::Private { diff --git a/Telegram/SourceFiles/platform/linux/notifications_manager_linux_dummy.cpp b/Telegram/SourceFiles/platform/linux/notifications_manager_linux_dummy.cpp index cc39a3a7b..a078b852f 100644 --- a/Telegram/SourceFiles/platform/linux/notifications_manager_linux_dummy.cpp +++ b/Telegram/SourceFiles/platform/linux/notifications_manager_linux_dummy.cpp @@ -33,13 +33,13 @@ bool Enforced() { return IsWayland(); } -std::unique_ptr Create( - Window::Notifications::System *system) { +void Create(Window::Notifications::System *system) { if (Enforced()) { - return std::make_unique(system); + using DummyManager = Window::Notifications::DummyManager; + system->setManager(std::make_unique(system)); + } else { + system->setManager(nullptr); } - - return nullptr; } } // namespace Notifications diff --git a/Telegram/SourceFiles/platform/linux/specific_linux.cpp b/Telegram/SourceFiles/platform/linux/specific_linux.cpp index 251d5db7b..c4c68a724 100644 --- a/Telegram/SourceFiles/platform/linux/specific_linux.cpp +++ b/Telegram/SourceFiles/platform/linux/specific_linux.cpp @@ -1247,18 +1247,13 @@ void start() { } #ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION - if (!IsNotificationServiceActivatable()) { - NSWInstance = std::make_unique< - internal::NotificationServiceWatcher>(); - } + NSWInstance = std::make_unique(); #endif // !DESKTOP_APP_DISABLE_DBUS_INTEGRATION } void finish() { #ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION - if (NSWInstance) { - NSWInstance = nullptr; - } + NSWInstance = nullptr; #endif // !DESKTOP_APP_DISABLE_DBUS_INTEGRATION } diff --git a/Telegram/SourceFiles/platform/mac/notifications_manager_mac.mm b/Telegram/SourceFiles/platform/mac/notifications_manager_mac.mm index 88d086066..dec09219e 100644 --- a/Telegram/SourceFiles/platform/mac/notifications_manager_mac.mm +++ b/Telegram/SourceFiles/platform/mac/notifications_manager_mac.mm @@ -166,11 +166,12 @@ bool Enforced() { return Supported(); } -std::unique_ptr Create(Window::Notifications::System *system) { +void Create(Window::Notifications::System *system) { if (Supported()) { - return std::make_unique(system); + system->setManager(std::make_unique(system)); + } else { + system->setManager(nullptr); } - return nullptr; } class Manager::Private : public QObject, private base::Subscriber { diff --git a/Telegram/SourceFiles/platform/platform_notifications_manager.h b/Telegram/SourceFiles/platform/platform_notifications_manager.h index cf8201ec7..2a4a7849f 100644 --- a/Telegram/SourceFiles/platform/platform_notifications_manager.h +++ b/Telegram/SourceFiles/platform/platform_notifications_manager.h @@ -18,8 +18,7 @@ namespace Notifications { [[nodiscard]] bool Supported(); [[nodiscard]] bool Enforced(); -[[nodiscard]] std::unique_ptr Create( - Window::Notifications::System *system); +void Create(Window::Notifications::System *system); } // namespace Notifications } // namespace Platform diff --git a/Telegram/SourceFiles/platform/win/notifications_manager_win.cpp b/Telegram/SourceFiles/platform/win/notifications_manager_win.cpp index ff631e954..fe0b73b72 100644 --- a/Telegram/SourceFiles/platform/win/notifications_manager_win.cpp +++ b/Telegram/SourceFiles/platform/win/notifications_manager_win.cpp @@ -329,16 +329,17 @@ bool Enforced() { return false; } -std::unique_ptr Create(Window::Notifications::System *system) { +void Create(Window::Notifications::System *system) { #ifndef __MINGW32__ if (Core::App().settings().nativeNotifications() && Supported()) { auto result = std::make_unique(system); if (result->init()) { - return std::move(result); + system->setManager(std::move(result)); + return; } } #endif // !__MINGW32__ - return nullptr; + system->setManager(nullptr); } #ifndef __MINGW32__ diff --git a/Telegram/SourceFiles/window/notifications_manager.cpp b/Telegram/SourceFiles/window/notifications_manager.cpp index 02d26f9b8..6b6b68034 100644 --- a/Telegram/SourceFiles/window/notifications_manager.cpp +++ b/Telegram/SourceFiles/window/notifications_manager.cpp @@ -66,12 +66,23 @@ System::System() } void System::createManager() { - _manager = Platform::Notifications::Create(this); + Platform::Notifications::Create(this); +} + +void System::setManager(std::unique_ptr manager) { + _manager = std::move(manager); if (!_manager) { _manager = std::make_unique(this); } } +std::optional System::managerType() const { + if (_manager) { + return _manager->type(); + } + return std::nullopt; +} + Main::Session *System::findSession(uint64 sessionId) const { for (const auto &[index, account] : Core::App().domain().accounts()) { if (const auto session = account->maybeSession()) { diff --git a/Telegram/SourceFiles/window/notifications_manager.h b/Telegram/SourceFiles/window/notifications_manager.h index f3953f95e..5e21ae30d 100644 --- a/Telegram/SourceFiles/window/notifications_manager.h +++ b/Telegram/SourceFiles/window/notifications_manager.h @@ -34,6 +34,12 @@ class Track; namespace Window { namespace Notifications { +enum class ManagerType { + Dummy, + Default, + Native, +}; + enum class ChangeType { SoundEnabled, FlashBounceEnabled, @@ -70,6 +76,8 @@ public: [[nodiscard]] Main::Session *findSession(uint64 sessionId) const; void createManager(); + void setManager(std::unique_ptr manager); + [[nodiscard]] std::optional managerType() const; void checkDelayed(); void schedule(not_null item); @@ -189,6 +197,8 @@ public: const QString &title, not_null session); + [[nodiscard]] virtual ManagerType type() const = 0; + virtual ~Manager() = default; protected: @@ -221,6 +231,11 @@ private: }; class NativeManager : public Manager { +public: + [[nodiscard]] ManagerType type() const override { + return ManagerType::Native; + } + protected: using Manager::Manager; @@ -252,6 +267,10 @@ class DummyManager : public NativeManager { public: using NativeManager::NativeManager; + [[nodiscard]] ManagerType type() const override { + return ManagerType::Dummy; + } + protected: void doShowNativeNotification( not_null peer, diff --git a/Telegram/SourceFiles/window/notifications_manager_default.h b/Telegram/SourceFiles/window/notifications_manager_default.h index 1950480f2..68d7c9614 100644 --- a/Telegram/SourceFiles/window/notifications_manager_default.h +++ b/Telegram/SourceFiles/window/notifications_manager_default.h @@ -43,6 +43,10 @@ public: Manager(System *system); ~Manager(); + [[nodiscard]] ManagerType type() const override { + return ManagerType::Default; + } + template void enumerateNotifications(Method method) { for (const auto ¬ification : _notifications) {