mirror of
https://github.com/telegramdesktop/tdesktop
synced 2025-04-23 15:47:41 +00:00
Recreate notification manager on notification service owner change
This commit is contained in:
parent
e55581e0c9
commit
49736cd879
@ -823,6 +823,8 @@ PRIVATE
|
|||||||
platform/linux/linux_gsd_media_keys.h
|
platform/linux/linux_gsd_media_keys.h
|
||||||
platform/linux/linux_libs.cpp
|
platform/linux/linux_libs.cpp
|
||||||
platform/linux/linux_libs.h
|
platform/linux/linux_libs.h
|
||||||
|
platform/linux/linux_notification_service_watcher.cpp
|
||||||
|
platform/linux/linux_notification_service_watcher.h
|
||||||
platform/linux/linux_wayland_integration.cpp
|
platform/linux/linux_wayland_integration.cpp
|
||||||
platform/linux/linux_wayland_integration.h
|
platform/linux/linux_wayland_integration.h
|
||||||
platform/linux/linux_xlib_helper.cpp
|
platform/linux/linux_xlib_helper.cpp
|
||||||
@ -1116,6 +1118,8 @@ if (LINUX AND DESKTOP_APP_DISABLE_DBUS_INTEGRATION)
|
|||||||
remove_target_sources(Telegram ${src_loc}
|
remove_target_sources(Telegram ${src_loc}
|
||||||
platform/linux/linux_gsd_media_keys.cpp
|
platform/linux/linux_gsd_media_keys.cpp
|
||||||
platform/linux/linux_gsd_media_keys.h
|
platform/linux/linux_gsd_media_keys.h
|
||||||
|
platform/linux/linux_notification_service_watcher.cpp
|
||||||
|
platform/linux/linux_notification_service_watcher.h
|
||||||
platform/linux/notifications_manager_linux.cpp
|
platform/linux/notifications_manager_linux.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
This file is part of Telegram Desktop,
|
||||||
|
the official desktop application for the Telegram messaging service.
|
||||||
|
|
||||||
|
For license and copyright information please follow this link:
|
||||||
|
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
*/
|
||||||
|
#include "platform/linux/linux_notification_service_watcher.h"
|
||||||
|
|
||||||
|
#include "core/application.h"
|
||||||
|
#include "main/main_domain.h"
|
||||||
|
#include "window/notifications_manager.h"
|
||||||
|
|
||||||
|
#include <QtDBus/QDBusConnection>
|
||||||
|
|
||||||
|
namespace Platform {
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
NotificationServiceWatcher::NotificationServiceWatcher()
|
||||||
|
: _dbusWatcher(
|
||||||
|
qsl("org.freedesktop.Notifications"),
|
||||||
|
QDBusConnection::sessionBus(),
|
||||||
|
QDBusServiceWatcher::WatchForOwnerChange) {
|
||||||
|
const auto signal = &QDBusServiceWatcher::serviceOwnerChanged;
|
||||||
|
QObject::connect(&_dbusWatcher, signal, [=] {
|
||||||
|
crl::on_main([=] {
|
||||||
|
if (!Core::App().domain().started()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Core::App().notifications().createManager();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
} // namespace Platform
|
@ -0,0 +1,24 @@
|
|||||||
|
/*
|
||||||
|
This file is part of Telegram Desktop,
|
||||||
|
the official desktop application for the Telegram messaging service.
|
||||||
|
|
||||||
|
For license and copyright information please follow this link:
|
||||||
|
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QtDBus/QDBusServiceWatcher>
|
||||||
|
|
||||||
|
namespace Platform {
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
class NotificationServiceWatcher {
|
||||||
|
public:
|
||||||
|
NotificationServiceWatcher();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QDBusServiceWatcher _dbusWatcher;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
} // namespace Platform
|
@ -19,6 +19,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||||||
|
|
||||||
#include <QtCore/QVersionNumber>
|
#include <QtCore/QVersionNumber>
|
||||||
#include <QtDBus/QDBusConnection>
|
#include <QtDBus/QDBusConnection>
|
||||||
|
#include <QtDBus/QDBusConnectionInterface>
|
||||||
#include <QtDBus/QDBusMessage>
|
#include <QtDBus/QDBusMessage>
|
||||||
#include <QtDBus/QDBusReply>
|
#include <QtDBus/QDBusReply>
|
||||||
#include <QtDBus/QDBusError>
|
#include <QtDBus/QDBusError>
|
||||||
@ -41,112 +42,89 @@ constexpr auto kPropertiesInterface = "org.freedesktop.DBus.Properties"_cs;
|
|||||||
constexpr auto kImageDataType = "(iiibii@ay)"_cs;
|
constexpr auto kImageDataType = "(iiibii@ay)"_cs;
|
||||||
constexpr auto kNotifyArgsType = "(susssasa{sv}i)"_cs;
|
constexpr auto kNotifyArgsType = "(susssasa{sv}i)"_cs;
|
||||||
|
|
||||||
bool NotificationsSupported = false;
|
bool ServiceRegistered = false;
|
||||||
bool InhibitedNotSupported = false;
|
bool InhibitedNotSupported = false;
|
||||||
|
std::vector<QString> CurrentServerInformation;
|
||||||
|
QStringList CurrentCapabilities;
|
||||||
|
|
||||||
void ComputeSupported(bool wait = false) {
|
bool GetServiceRegistered() {
|
||||||
const auto message = QDBusMessage::createMethodCall(
|
const auto interface = QDBusConnection::sessionBus().interface();
|
||||||
kService.utf16(),
|
const auto activatable = IsNotificationServiceActivatable();
|
||||||
kObjectPath.utf16(),
|
|
||||||
kInterface.utf16(),
|
|
||||||
qsl("GetServerInformation"));
|
|
||||||
|
|
||||||
auto async = QDBusConnection::sessionBus().asyncCall(message);
|
return interface
|
||||||
auto watcher = new QDBusPendingCallWatcher(async);
|
? interface->isServiceRegistered(kService.utf16()) || activatable
|
||||||
|
: activatable;
|
||||||
QObject::connect(
|
|
||||||
watcher,
|
|
||||||
&QDBusPendingCallWatcher::finished,
|
|
||||||
[=](QDBusPendingCallWatcher *call) {
|
|
||||||
QDBusPendingReply<
|
|
||||||
QString,
|
|
||||||
QString,
|
|
||||||
QString,
|
|
||||||
QString> reply = *call;
|
|
||||||
|
|
||||||
if (reply.isValid()) {
|
|
||||||
NotificationsSupported = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
call->deleteLater();
|
|
||||||
});
|
|
||||||
|
|
||||||
if (wait) {
|
|
||||||
watcher->waitForFinished();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void GetSupported() {
|
|
||||||
static auto Checked = false;
|
|
||||||
if (Checked) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Checked = true;
|
|
||||||
|
|
||||||
if (Core::App().settings().nativeNotifications() && !IsWayland()) {
|
|
||||||
ComputeSupported(true);
|
|
||||||
} else {
|
|
||||||
ComputeSupported();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<QString> ComputeServerInformation() {
|
|
||||||
std::vector<QString> serverInformation;
|
|
||||||
|
|
||||||
const auto message = QDBusMessage::createMethodCall(
|
|
||||||
kService.utf16(),
|
|
||||||
kObjectPath.utf16(),
|
|
||||||
kInterface.utf16(),
|
|
||||||
qsl("GetServerInformation"));
|
|
||||||
|
|
||||||
const auto reply = QDBusConnection::sessionBus().call(message);
|
|
||||||
|
|
||||||
if (reply.type() == QDBusMessage::ReplyMessage) {
|
|
||||||
ranges::transform(
|
|
||||||
reply.arguments(),
|
|
||||||
ranges::back_inserter(serverInformation),
|
|
||||||
&QVariant::toString
|
|
||||||
);
|
|
||||||
} else if (reply.type() == QDBusMessage::ErrorMessage) {
|
|
||||||
LOG(("Native notification error: %1").arg(reply.errorMessage()));
|
|
||||||
} else {
|
|
||||||
LOG(("Native notification error: "
|
|
||||||
"invalid reply from GetServerInformation"));
|
|
||||||
}
|
|
||||||
|
|
||||||
return serverInformation;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<QString> GetServerInformation() {
|
std::vector<QString> GetServerInformation() {
|
||||||
static const auto Result = ComputeServerInformation();
|
std::vector<QString> result;
|
||||||
return Result;
|
|
||||||
|
const auto message = QDBusMessage::createMethodCall(
|
||||||
|
kService.utf16(),
|
||||||
|
kObjectPath.utf16(),
|
||||||
|
kInterface.utf16(),
|
||||||
|
qsl("GetServerInformation"));
|
||||||
|
|
||||||
|
// We may be launched earlier than notification daemon
|
||||||
|
while (true) {
|
||||||
|
const auto reply = QDBusConnection::sessionBus().call(message);
|
||||||
|
|
||||||
|
if (reply.type() == QDBusMessage::ReplyMessage) {
|
||||||
|
ranges::transform(
|
||||||
|
reply.arguments(),
|
||||||
|
ranges::back_inserter(result),
|
||||||
|
&QVariant::toString);
|
||||||
|
} else if (reply.type() == QDBusMessage::ErrorMessage) {
|
||||||
|
LOG(("Native notification error: %1").arg(reply.errorMessage()));
|
||||||
|
|
||||||
|
if (reply.errorName()
|
||||||
|
== qsl("org.freedesktop.DBus.Error.NoReply")) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LOG(("Native notification error: "
|
||||||
|
"invalid reply from GetServerInformation"));
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList ComputeCapabilities() {
|
QStringList GetCapabilities() {
|
||||||
const auto message = QDBusMessage::createMethodCall(
|
const auto message = QDBusMessage::createMethodCall(
|
||||||
kService.utf16(),
|
kService.utf16(),
|
||||||
kObjectPath.utf16(),
|
kObjectPath.utf16(),
|
||||||
kInterface.utf16(),
|
kInterface.utf16(),
|
||||||
qsl("GetCapabilities"));
|
qsl("GetCapabilities"));
|
||||||
|
|
||||||
const QDBusReply<QStringList> reply = QDBusConnection::sessionBus().call(
|
// We may be launched earlier than notification daemon
|
||||||
message);
|
while (true) {
|
||||||
|
const QDBusReply<QStringList> reply = QDBusConnection::sessionBus()
|
||||||
|
.call(message);
|
||||||
|
|
||||||
|
if (reply.isValid()) {
|
||||||
|
return reply.value();
|
||||||
|
}
|
||||||
|
|
||||||
if (reply.isValid()) {
|
|
||||||
return reply.value();
|
|
||||||
} else {
|
|
||||||
LOG(("Native notification error: %1").arg(reply.error().message()));
|
LOG(("Native notification error: %1").arg(reply.error().message()));
|
||||||
|
|
||||||
|
if (reply.error().type() != QDBusError::NoReply) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList GetCapabilities() {
|
|
||||||
static const auto Result = ComputeCapabilities();
|
|
||||||
return Result;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Inhibited() {
|
bool Inhibited() {
|
||||||
|
if (!Supported()
|
||||||
|
|| !CurrentCapabilities.contains(qsl("inhibitions"))
|
||||||
|
|| InhibitedNotSupported) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
auto message = QDBusMessage::createMethodCall(
|
auto message = QDBusMessage::createMethodCall(
|
||||||
kService.utf16(),
|
kService.utf16(),
|
||||||
kObjectPath.utf16(),
|
kObjectPath.utf16(),
|
||||||
@ -277,8 +255,7 @@ NotificationData::NotificationData(
|
|||||||
bool hideReplyButton)
|
bool hideReplyButton)
|
||||||
: _manager(manager)
|
: _manager(manager)
|
||||||
, _title(title)
|
, _title(title)
|
||||||
, _imageKey(GetImageKey(ParseSpecificationVersion(
|
, _imageKey(GetImageKey(ParseSpecificationVersion(CurrentServerInformation)))
|
||||||
GetServerInformation())))
|
|
||||||
, _id(id) {
|
, _id(id) {
|
||||||
GError *error = nullptr;
|
GError *error = nullptr;
|
||||||
|
|
||||||
@ -293,7 +270,7 @@ NotificationData::NotificationData(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto capabilities = GetCapabilities();
|
const auto capabilities = CurrentCapabilities;
|
||||||
|
|
||||||
if (capabilities.contains(qsl("body-markup"))) {
|
if (capabilities.contains(qsl("body-markup"))) {
|
||||||
_body = subtitle.isEmpty()
|
_body = subtitle.isEmpty()
|
||||||
@ -613,30 +590,33 @@ void NotificationData::notificationReplied(uint id, const QString &text) {
|
|||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
bool SkipAudio() {
|
bool SkipAudio() {
|
||||||
if (Supported()
|
return Inhibited();
|
||||||
&& GetCapabilities().contains(qsl("inhibitions"))
|
|
||||||
&& !InhibitedNotSupported) {
|
|
||||||
return Inhibited();
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SkipToast() {
|
bool SkipToast() {
|
||||||
return SkipAudio();
|
return Inhibited();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SkipFlashBounce() {
|
bool SkipFlashBounce() {
|
||||||
return SkipAudio();
|
return Inhibited();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Supported() {
|
bool Supported() {
|
||||||
return NotificationsSupported;
|
return ServiceRegistered;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<Window::Notifications::Manager> Create(
|
std::unique_ptr<Window::Notifications::Manager> Create(
|
||||||
Window::Notifications::System *system) {
|
Window::Notifications::System *system) {
|
||||||
GetSupported();
|
ServiceRegistered = GetServiceRegistered();
|
||||||
|
InhibitedNotSupported = false;
|
||||||
|
|
||||||
|
if (Supported()) {
|
||||||
|
CurrentServerInformation = GetServerInformation();
|
||||||
|
CurrentCapabilities = GetCapabilities();
|
||||||
|
} else {
|
||||||
|
CurrentServerInformation = {};
|
||||||
|
CurrentCapabilities = QStringList{};
|
||||||
|
}
|
||||||
|
|
||||||
if ((Core::App().settings().nativeNotifications() && Supported())
|
if ((Core::App().settings().nativeNotifications() && Supported())
|
||||||
|| IsWayland()) {
|
|| IsWayland()) {
|
||||||
@ -683,8 +663,8 @@ Manager::Private::Private(not_null<Manager*> manager, Type type)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto serverInformation = GetServerInformation();
|
const auto serverInformation = CurrentServerInformation;
|
||||||
const auto capabilities = GetCapabilities();
|
const auto capabilities = CurrentCapabilities;
|
||||||
|
|
||||||
if (!serverInformation.empty()) {
|
if (!serverInformation.empty()) {
|
||||||
LOG(("Notification daemon product name: %1")
|
LOG(("Notification daemon product name: %1")
|
||||||
|
@ -25,6 +25,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||||||
#include "core/application.h"
|
#include "core/application.h"
|
||||||
|
|
||||||
#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION
|
#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION
|
||||||
|
#include "platform/linux/linux_notification_service_watcher.h"
|
||||||
#include "platform/linux/linux_gsd_media_keys.h"
|
#include "platform/linux/linux_gsd_media_keys.h"
|
||||||
#endif // !DESKTOP_APP_DISABLE_DBUS_INTEGRATION
|
#endif // !DESKTOP_APP_DISABLE_DBUS_INTEGRATION
|
||||||
|
|
||||||
@ -87,6 +88,8 @@ constexpr auto kXCBFrameExtentsAtomName = "_GTK_FRAME_EXTENTS"_cs;
|
|||||||
QStringList PlatformThemes;
|
QStringList PlatformThemes;
|
||||||
|
|
||||||
#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION
|
#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION
|
||||||
|
std::unique_ptr<internal::NotificationServiceWatcher> NSWInstance;
|
||||||
|
|
||||||
QStringList ListDBusActivatableNames() {
|
QStringList ListDBusActivatableNames() {
|
||||||
static const auto Result = [&] {
|
static const auto Result = [&] {
|
||||||
const auto message = QDBusMessage::createMethodCall(
|
const auto message = QDBusMessage::createMethodCall(
|
||||||
@ -632,6 +635,17 @@ bool CanOpenDirectoryWithPortal() {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IsNotificationServiceActivatable() {
|
||||||
|
#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION
|
||||||
|
static const auto Result = ListDBusActivatableNames().contains(
|
||||||
|
qsl("org.freedesktop.Notifications"));
|
||||||
|
|
||||||
|
return Result;
|
||||||
|
#endif // !DESKTOP_APP_DISABLE_DBUS_INTEGRATION
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
QString AppRuntimeDirectory() {
|
QString AppRuntimeDirectory() {
|
||||||
static const auto Result = [&] {
|
static const auto Result = [&] {
|
||||||
auto runtimeDir = QStandardPaths::writableLocation(
|
auto runtimeDir = QStandardPaths::writableLocation(
|
||||||
@ -1231,9 +1245,21 @@ void start() {
|
|||||||
if (const auto waylandIntegration = WaylandIntegration::Instance()) {
|
if (const auto waylandIntegration = WaylandIntegration::Instance()) {
|
||||||
waylandIntegration->waitForInterfaceAnnounce();
|
waylandIntegration->waitForInterfaceAnnounce();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION
|
||||||
|
if (!IsNotificationServiceActivatable()) {
|
||||||
|
NSWInstance = std::make_unique<
|
||||||
|
internal::NotificationServiceWatcher>();
|
||||||
|
}
|
||||||
|
#endif // !DESKTOP_APP_DISABLE_DBUS_INTEGRATION
|
||||||
}
|
}
|
||||||
|
|
||||||
void finish() {
|
void finish() {
|
||||||
|
#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION
|
||||||
|
if (NSWInstance) {
|
||||||
|
NSWInstance = nullptr;
|
||||||
|
}
|
||||||
|
#endif // !DESKTOP_APP_DISABLE_DBUS_INTEGRATION
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace ThirdParty
|
} // namespace ThirdParty
|
||||||
|
@ -25,6 +25,7 @@ bool UseGtkIntegration();
|
|||||||
bool IsGtkIntegrationForced();
|
bool IsGtkIntegrationForced();
|
||||||
bool UseXDGDesktopPortal();
|
bool UseXDGDesktopPortal();
|
||||||
bool CanOpenDirectoryWithPortal();
|
bool CanOpenDirectoryWithPortal();
|
||||||
|
bool IsNotificationServiceActivatable();
|
||||||
|
|
||||||
QString AppRuntimeDirectory();
|
QString AppRuntimeDirectory();
|
||||||
QString GetLauncherBasename();
|
QString GetLauncherBasename();
|
||||||
|
Loading…
Reference in New Issue
Block a user