mirror of
https://hubproxy.babadafafafafa.cn/https://github.com/telegramdesktop/tdesktop
synced 2026-09-21 00:23:56 +08:00
Support GNotification
It's used if there's a gtk notification daemon or application is running sandboxed without access to the freedesktop protocol. GNotification API is poor, but should feel native on environments using GNOME technologies.
This commit is contained in:
@@ -9,10 +9,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "platform/linux/notifications_manager_linux.h"
|
||||
|
||||
#include "window/notifications_utilities.h"
|
||||
#include "base/options.h"
|
||||
#include "base/platform/base_platform_info.h"
|
||||
#include "base/platform/linux/base_linux_glibmm_helper.h"
|
||||
#include "base/platform/linux/base_linux_dbus_utilities.h"
|
||||
#include "platform/platform_specific.h"
|
||||
#include "core/application.h"
|
||||
#include "core/sandbox.h"
|
||||
#include "core/core_settings.h"
|
||||
#include "data/data_forum_topic.h"
|
||||
#include "history/history.h"
|
||||
@@ -27,6 +30,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include <glibmm.h>
|
||||
#include <giomm.h>
|
||||
|
||||
#include <dlfcn.h>
|
||||
|
||||
namespace Platform {
|
||||
namespace Notifications {
|
||||
namespace {
|
||||
@@ -341,6 +346,9 @@ private:
|
||||
const not_null<Manager*> _manager;
|
||||
NotificationId _id;
|
||||
|
||||
Glib::RefPtr<Gio::Application> _application;
|
||||
Glib::RefPtr<Gio::Notification> _notification;
|
||||
|
||||
Glib::RefPtr<Gio::DBus::Connection> _dbusConnection;
|
||||
Glib::ustring _title;
|
||||
Glib::ustring _body;
|
||||
@@ -367,7 +375,8 @@ NotificationData::NotificationData(
|
||||
not_null<Manager*> manager,
|
||||
NotificationId id)
|
||||
: _manager(manager)
|
||||
, _id(id) {
|
||||
, _id(id)
|
||||
, _application(Gio::Application::get_default()) {
|
||||
}
|
||||
|
||||
bool NotificationData::init(
|
||||
@@ -375,6 +384,64 @@ bool NotificationData::init(
|
||||
const QString &subtitle,
|
||||
const QString &msg,
|
||||
Window::Notifications::Manager::DisplayOptions options) {
|
||||
if (_application) {
|
||||
_notification = Gio::Notification::create(title.toStdString());
|
||||
|
||||
_notification->set_body(
|
||||
subtitle.isEmpty()
|
||||
? msg.toStdString()
|
||||
: qsl("%1\n%2").arg(subtitle, msg).toStdString());
|
||||
|
||||
_notification->set_icon(
|
||||
Gio::ThemedIcon::create(base::IconName().toStdString()));
|
||||
|
||||
// glib 2.42+, we keep glib 2.40+ compatibility
|
||||
static const auto set_priority = [] {
|
||||
// reset dlerror after dlsym call
|
||||
const auto guard = gsl::finally([] { dlerror(); });
|
||||
return reinterpret_cast<decltype(&g_notification_set_priority)>(
|
||||
dlsym(RTLD_DEFAULT, "g_notification_set_priority"));
|
||||
}();
|
||||
|
||||
if (set_priority) {
|
||||
// for chat messages, according to
|
||||
// https://docs.gtk.org/gio/enum.NotificationPriority.html
|
||||
set_priority(_notification->gobj(), G_NOTIFICATION_PRIORITY_HIGH);
|
||||
}
|
||||
|
||||
// glib 2.70+, we keep glib 2.40+ compatibility
|
||||
static const auto set_category = [] {
|
||||
// reset dlerror after dlsym call
|
||||
const auto guard = gsl::finally([] { dlerror(); });
|
||||
return reinterpret_cast<decltype(&g_notification_set_category)>(
|
||||
dlsym(RTLD_DEFAULT, "g_notification_set_category"));
|
||||
}();
|
||||
|
||||
if (set_category) {
|
||||
set_category(_notification->gobj(), "im.received");
|
||||
}
|
||||
|
||||
const auto idTuple = _id.toTuple();
|
||||
|
||||
_notification->set_default_action(
|
||||
"app.notification-reply",
|
||||
idTuple);
|
||||
|
||||
if (!options.hideMarkAsRead) {
|
||||
_notification->add_button(
|
||||
tr::lng_context_mark_read(tr::now).toStdString(),
|
||||
"app.notification-mark-as-read",
|
||||
idTuple);
|
||||
}
|
||||
|
||||
_notification->add_button(
|
||||
tr::lng_notification_reply(tr::now).toStdString(),
|
||||
"app.notification-reply",
|
||||
idTuple);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Noexcept([&] {
|
||||
_dbusConnection = Gio::DBus::Connection::get_sync(
|
||||
Gio::DBus::BusType::SESSION);
|
||||
@@ -545,6 +612,17 @@ NotificationData::~NotificationData() {
|
||||
}
|
||||
|
||||
void NotificationData::show() {
|
||||
if (_application && _notification) {
|
||||
_application->send_notification(
|
||||
std::to_string(_id.contextId.sessionId)
|
||||
+ '-'
|
||||
+ std::to_string(_id.contextId.peerId.value)
|
||||
+ '-'
|
||||
+ std::to_string(_id.msgId.bare),
|
||||
_notification);
|
||||
return;
|
||||
}
|
||||
|
||||
// a hack for snap's activation restriction
|
||||
const auto weak = base::make_weak(this);
|
||||
StartServiceAsync(crl::guard(weak, [=] {
|
||||
@@ -587,6 +665,17 @@ void NotificationData::show() {
|
||||
}
|
||||
|
||||
void NotificationData::close() {
|
||||
if (_application) {
|
||||
_application->withdraw_notification(
|
||||
std::to_string(_id.contextId.sessionId)
|
||||
+ '-'
|
||||
+ std::to_string(_id.contextId.peerId.value)
|
||||
+ '-'
|
||||
+ std::to_string(_id.msgId.bare));
|
||||
_manager->clearNotification(_id);
|
||||
return;
|
||||
}
|
||||
|
||||
_dbusConnection->call(
|
||||
std::string(kObjectPath),
|
||||
std::string(kInterface),
|
||||
@@ -602,7 +691,16 @@ void NotificationData::close() {
|
||||
}
|
||||
|
||||
void NotificationData::setImage(const QString &imagePath) {
|
||||
if (imagePath.isEmpty() || _imageKey.empty()) {
|
||||
if (imagePath.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (_notification) {
|
||||
_notification->set_icon(Gio::Icon::create(imagePath.toStdString()));
|
||||
return;
|
||||
}
|
||||
|
||||
if (_imageKey.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -696,13 +794,13 @@ bool SkipFlashBounceForCustom() {
|
||||
}
|
||||
|
||||
bool Supported() {
|
||||
return ServiceRegistered;
|
||||
return ServiceRegistered || Gio::Application::get_default();
|
||||
}
|
||||
|
||||
bool Enforced() {
|
||||
// Wayland doesn't support positioning
|
||||
// and custom notifications don't work here
|
||||
return IsWayland();
|
||||
return IsWayland() || OptionGApplication.value();
|
||||
}
|
||||
|
||||
bool ByDefault() {
|
||||
@@ -728,25 +826,30 @@ bool ByDefault() {
|
||||
}
|
||||
|
||||
void Create(Window::Notifications::System *system) {
|
||||
static const auto ServiceWatcher = CreateServiceWatcher();
|
||||
|
||||
const auto managerSetter = [=] {
|
||||
using ManagerType = Window::Notifications::ManagerType;
|
||||
if ((Core::App().settings().nativeNotifications() || Enforced())
|
||||
&& Supported()) {
|
||||
if (system->managerType() != ManagerType::Native) {
|
||||
if (system->manager().type() != ManagerType::Native) {
|
||||
system->setManager(std::make_unique<Manager>(system));
|
||||
}
|
||||
} else if (Enforced()) {
|
||||
if (system->managerType() != ManagerType::Dummy) {
|
||||
if (system->manager().type() != ManagerType::Dummy) {
|
||||
using DummyManager = Window::Notifications::DummyManager;
|
||||
system->setManager(std::make_unique<DummyManager>(system));
|
||||
}
|
||||
} else if (system->managerType() != ManagerType::Default) {
|
||||
} else if (system->manager().type() != ManagerType::Default) {
|
||||
system->setManager(nullptr);
|
||||
}
|
||||
};
|
||||
|
||||
if (Gio::Application::get_default()) {
|
||||
managerSetter();
|
||||
return;
|
||||
}
|
||||
|
||||
static const auto ServiceWatcher = CreateServiceWatcher();
|
||||
|
||||
const auto counter = std::make_shared<int>(2);
|
||||
const auto oneReady = [=] {
|
||||
if (!--*counter) {
|
||||
@@ -1098,7 +1201,7 @@ void Manager::doClearFromSession(not_null<Main::Session*> session) {
|
||||
}
|
||||
|
||||
bool Manager::doSkipAudio() const {
|
||||
return _private->inhibited();
|
||||
return _private->inhibited() || Gio::Application::get_default();
|
||||
}
|
||||
|
||||
bool Manager::doSkipToast() const {
|
||||
@@ -1106,7 +1209,7 @@ bool Manager::doSkipToast() const {
|
||||
}
|
||||
|
||||
bool Manager::doSkipFlashBounce() const {
|
||||
return _private->inhibited();
|
||||
return _private->inhibited() || Gio::Application::get_default();
|
||||
}
|
||||
|
||||
} // namespace Notifications
|
||||
|
||||
Reference in New Issue
Block a user