2
0
mirror of https://github.com/telegramdesktop/tdesktop synced 2025-08-31 14:38:15 +00:00

Make notification manager creation async

This commit is contained in:
Ilya Fedin
2021-01-21 14:18:40 +04:00
committed by John Preston
parent a0a71687e7
commit e8edbb16ae
10 changed files with 152 additions and 82 deletions

View File

@@ -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 <QtDBus/QDBusConnection>
@@ -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();

View File

@@ -21,6 +21,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include <QtDBus/QDBusConnection>
#include <QtDBus/QDBusConnectionInterface>
#include <QtDBus/QDBusMessage>
#include <QtDBus/QDBusPendingCall>
#include <QtDBus/QDBusPendingCallWatcher>
#include <QtDBus/QDBusPendingReply>
#include <QtDBus/QDBusReply>
#include <QtDBus/QDBusError>
@@ -64,7 +66,7 @@ bool GetServiceRegistered() {
: activatable;
}
std::optional<ServerInformation> GetServerInformation() {
void GetServerInformation(Fn<void(std::optional<ServerInformation>)> callback) {
using ServerInformationReply = QDBusPendingReply<
QString,
QString,
@@ -77,59 +79,63 @@ std::optional<ServerInformation> 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<void(QStringList)> 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<QStringList> reply = QDBusConnection::sessionBus()
.call(message);
const auto async = QDBusConnection::sessionBus().asyncCall(message);
auto watcher = new QDBusPendingCallWatcher(async);
const auto finished = [=](QDBusPendingCallWatcher *call) {
const QDBusPendingReply<QStringList> 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<void(bool)> 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<QVariant>(*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<Window::Notifications::Manager> 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<Manager>(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<DummyManager>(system));
}
if (ServiceRegistered) {
const auto counter = std::make_shared<int>(3);
const auto oneReady = [=] {
if (!--*counter) {
managerSetter();
}
};
GetServerInformation([=](std::optional<ServerInformation> 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<Manager>(system);
}
return nullptr;
}
class Manager::Private {

View File

@@ -33,13 +33,13 @@ bool Enforced() {
return IsWayland();
}
std::unique_ptr<Window::Notifications::Manager> Create(
Window::Notifications::System *system) {
void Create(Window::Notifications::System *system) {
if (Enforced()) {
return std::make_unique<Window::Notifications::DummyManager>(system);
using DummyManager = Window::Notifications::DummyManager;
system->setManager(std::make_unique<DummyManager>(system));
} else {
system->setManager(nullptr);
}
return nullptr;
}
} // namespace Notifications

View File

@@ -1247,18 +1247,13 @@ void start() {
}
#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION
if (!IsNotificationServiceActivatable()) {
NSWInstance = std::make_unique<
internal::NotificationServiceWatcher>();
}
NSWInstance = std::make_unique<internal::NotificationServiceWatcher>();
#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
}