mirror of https://github.com/procxx/kepka.git
Native notifications switched off by default. Libnotify supported.
This commit is contained in:
parent
6db52f7fa9
commit
c9288f2d0a
|
@ -244,6 +244,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
|||
"lng_settings_show_name" = "Show sender's name";
|
||||
"lng_settings_show_preview" = "Show message preview";
|
||||
"lng_settings_use_windows" = "Use Windows notifications";
|
||||
"lng_settings_use_native_notifications" = "Use native notifications";
|
||||
"lng_settings_sound_notify" = "Play sound";
|
||||
"lng_settings_include_muted" = "Include muted chats in unread count";
|
||||
|
||||
|
|
|
@ -634,7 +634,7 @@ struct Data {
|
|||
bool RestoreSoundNotifyFromTray = false;
|
||||
bool IncludeMuted = true;
|
||||
DBINotifyView NotifyView = dbinvShowPreview;
|
||||
bool WindowsNotifications = true;
|
||||
bool NativeNotifications = false;
|
||||
base::Observable<Notify::ChangeType> NotifySettingsChanged;
|
||||
|
||||
DBIConnectionType ConnectionType = dbictAuto;
|
||||
|
@ -741,7 +741,7 @@ DefineVar(Global, bool, DesktopNotify);
|
|||
DefineVar(Global, bool, RestoreSoundNotifyFromTray);
|
||||
DefineVar(Global, bool, IncludeMuted);
|
||||
DefineVar(Global, DBINotifyView, NotifyView);
|
||||
DefineVar(Global, bool, WindowsNotifications);
|
||||
DefineVar(Global, bool, NativeNotifications);
|
||||
DefineRefVar(Global, base::Observable<Notify::ChangeType>, NotifySettingsChanged);
|
||||
|
||||
DefineVar(Global, DBIConnectionType, ConnectionType);
|
||||
|
|
|
@ -307,7 +307,7 @@ DeclareVar(bool, DesktopNotify);
|
|||
DeclareVar(bool, RestoreSoundNotifyFromTray);
|
||||
DeclareVar(bool, IncludeMuted);
|
||||
DeclareVar(DBINotifyView, NotifyView);
|
||||
DeclareVar(bool, WindowsNotifications);
|
||||
DeclareVar(bool, NativeNotifications);
|
||||
DeclareRefVar(base::Observable<Notify::ChangeType>, NotifySettingsChanged);
|
||||
|
||||
DeclareVar(DBIConnectionType, ConnectionType);
|
||||
|
|
|
@ -534,7 +534,7 @@ enum {
|
|||
dbiDcOption = 0x27,
|
||||
dbiTryIPv6 = 0x28,
|
||||
dbiSongVolume = 0x29,
|
||||
dbiWindowsNotifications = 0x30,
|
||||
dbiWindowsNotificationsOld = 0x30,
|
||||
dbiIncludeMuted = 0x31,
|
||||
dbiMegagroupSizeMax = 0x32,
|
||||
dbiDownloadPath = 0x33,
|
||||
|
@ -548,6 +548,7 @@ enum {
|
|||
dbiModerateMode = 0x41,
|
||||
dbiVideoVolume = 0x42,
|
||||
dbiStickersRecentLimit = 0x43,
|
||||
dbiNativeNotifications = 0x44,
|
||||
|
||||
dbiEncryptedWithSalt = 333,
|
||||
dbiEncrypted = 444,
|
||||
|
@ -989,12 +990,18 @@ bool _readSetting(quint32 blockId, QDataStream &stream, int version) {
|
|||
if (App::wnd()) App::wnd()->updateTrayMenu();
|
||||
} break;
|
||||
|
||||
case dbiWindowsNotifications: {
|
||||
case dbiWindowsNotificationsOld: {
|
||||
qint32 v;
|
||||
stream >> v;
|
||||
if (!_checkStreamStatus(stream)) return false;
|
||||
} break;
|
||||
|
||||
case dbiNativeNotifications: {
|
||||
qint32 v;
|
||||
stream >> v;
|
||||
if (!_checkStreamStatus(stream)) return false;
|
||||
|
||||
Global::SetWindowsNotifications(v == 1);
|
||||
Global::SetNativeNotifications(v == 1);
|
||||
} break;
|
||||
|
||||
case dbiWorkMode: {
|
||||
|
@ -1589,7 +1596,7 @@ void _writeUserSettings() {
|
|||
data.stream << quint32(dbiShowingSavedGifs) << qint32(cShowingSavedGifs());
|
||||
data.stream << quint32(dbiDesktopNotify) << qint32(Global::DesktopNotify());
|
||||
data.stream << quint32(dbiNotifyView) << qint32(Global::NotifyView());
|
||||
data.stream << quint32(dbiWindowsNotifications) << qint32(Global::WindowsNotifications());
|
||||
data.stream << quint32(dbiNativeNotifications) << qint32(Global::NativeNotifications());
|
||||
data.stream << quint32(dbiAskDownloadPath) << qint32(Global::AskDownloadPath());
|
||||
data.stream << quint32(dbiDownloadPath) << (Global::AskDownloadPath() ? QString() : Global::DownloadPath()) << (Global::AskDownloadPath() ? QByteArray() : Global::DownloadPathBookmark());
|
||||
data.stream << quint32(dbiCompressPastedImage) << qint32(cCompressPastedImage());
|
||||
|
|
|
@ -80,7 +80,11 @@ void startLibNotify() {
|
|||
|
||||
QLibrary lib_notify;
|
||||
if (!loadLibrary(lib_notify, "notify", 4)) {
|
||||
return;
|
||||
if (!loadLibrary(lib_notify, "notify", 5)) {
|
||||
if (!loadLibrary(lib_notify, "notify", 1)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
load(lib_notify, "notify_init", notify_init);
|
||||
|
|
|
@ -93,10 +93,16 @@ bool setupGtkBase(QLibrary &lib_gtk) {
|
|||
if (!load(lib_gtk, "g_type_check_instance_cast", g_type_check_instance_cast)) return false;
|
||||
if (!load(lib_gtk, "g_type_check_instance_is_a", g_type_check_instance_is_a)) return false;
|
||||
if (!load(lib_gtk, "g_signal_connect_data", g_signal_connect_data)) return false;
|
||||
if (!load(lib_gtk, "g_signal_handler_disconnect", g_signal_handler_disconnect)) return false;
|
||||
|
||||
if (!load(lib_gtk, "g_object_ref_sink", g_object_ref_sink)) return false;
|
||||
if (!load(lib_gtk, "g_object_unref", g_object_unref)) return false;
|
||||
if (!load(lib_gtk, "g_free", g_free)) return false;
|
||||
if (!load(lib_gtk, "g_list_foreach", g_list_foreach)) return false;
|
||||
if (!load(lib_gtk, "g_list_free", g_list_free)) return false;
|
||||
if (!load(lib_gtk, "g_list_free_full", g_list_free_full)) return false;
|
||||
|
||||
if (!load(lib_gtk, "g_error_free", g_error_free)) return false;
|
||||
if (!load(lib_gtk, "g_slist_free", g_slist_free)) return false;
|
||||
|
||||
DEBUG_LOG(("Library gtk functions loaded!"));
|
||||
|
@ -170,6 +176,7 @@ f_gtk_dialog_run gtk_dialog_run = nullptr;
|
|||
f_g_type_check_instance_cast g_type_check_instance_cast = nullptr;
|
||||
f_g_type_check_instance_is_a g_type_check_instance_is_a = nullptr;
|
||||
f_g_signal_connect_data g_signal_connect_data = nullptr;
|
||||
f_g_signal_handler_disconnect g_signal_handler_disconnect = nullptr;
|
||||
f_app_indicator_new app_indicator_new = nullptr;
|
||||
f_app_indicator_set_status app_indicator_set_status = nullptr;
|
||||
f_app_indicator_set_menu app_indicator_set_menu = nullptr;
|
||||
|
@ -193,6 +200,10 @@ f_g_object_ref_sink g_object_ref_sink = nullptr;
|
|||
f_g_object_unref g_object_unref = nullptr;
|
||||
f_g_idle_add g_idle_add = nullptr;
|
||||
f_g_free g_free = nullptr;
|
||||
f_g_list_foreach g_list_foreach = nullptr;
|
||||
f_g_list_free g_list_free = nullptr;
|
||||
f_g_list_free_full g_list_free_full = nullptr;
|
||||
f_g_error_free g_error_free = nullptr;
|
||||
f_g_slist_free g_slist_free = nullptr;
|
||||
#ifndef TDESKTOP_DISABLE_UNITY_INTEGRATION
|
||||
f_unity_launcher_entry_set_count unity_launcher_entry_set_count = nullptr;
|
||||
|
|
|
@ -255,6 +255,9 @@ inline gulong g_signal_connect_swapped_helper(gpointer instance, const gchar *de
|
|||
return g_signal_connect_data(instance, detailed_signal, c_handler, data, NULL, G_CONNECT_SWAPPED);
|
||||
}
|
||||
|
||||
typedef void (*f_g_signal_handler_disconnect)(gpointer instance, gulong handler_id);
|
||||
extern f_g_signal_handler_disconnect g_signal_handler_disconnect;
|
||||
|
||||
typedef AppIndicator* (*f_app_indicator_new)(const gchar *id, const gchar *icon_name, AppIndicatorCategory category);
|
||||
extern f_app_indicator_new app_indicator_new;
|
||||
|
||||
|
@ -324,6 +327,18 @@ extern f_g_idle_add g_idle_add;
|
|||
typedef void (*f_g_free)(gpointer mem);
|
||||
extern f_g_free g_free;
|
||||
|
||||
typedef void (*f_g_list_foreach)(GList *list, GFunc func, gpointer user_data);
|
||||
extern f_g_list_foreach g_list_foreach;
|
||||
|
||||
typedef void (*f_g_list_free)(GList *list);
|
||||
extern f_g_list_free g_list_free;
|
||||
|
||||
typedef void (*f_g_list_free_full)(GList *list, GDestroyNotify free_func);
|
||||
extern f_g_list_free_full g_list_free_full;
|
||||
|
||||
typedef void (*f_g_error_free)(GError *error);
|
||||
extern f_g_error_free g_error_free;
|
||||
|
||||
typedef void (*f_g_slist_free)(GSList *list);
|
||||
extern f_g_slist_free g_slist_free;
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
|||
#include "platform/linux/main_window_linux.h"
|
||||
|
||||
#include "platform/linux/linux_libs.h"
|
||||
#include "platform/platform_notifications_manager.h"
|
||||
#include "mainwindow.h"
|
||||
#include "application.h"
|
||||
#include "lang.h"
|
||||
|
@ -355,6 +356,10 @@ void MainWindow::psUpdateCounter() {
|
|||
}
|
||||
}
|
||||
|
||||
bool MainWindow::psHasNativeNotifications() {
|
||||
return Notifications::supported();
|
||||
}
|
||||
|
||||
void MainWindow::LibsLoaded() {
|
||||
QString cdesktop = QString(getenv("XDG_CURRENT_DESKTOP")).toLower();
|
||||
noQtTrayIcon = (cdesktop == qstr("pantheon")) || (cdesktop == qstr("gnome"));
|
||||
|
|
|
@ -58,9 +58,7 @@ public:
|
|||
|
||||
void psUpdateCounter();
|
||||
|
||||
bool psHasNativeNotifications() {
|
||||
return false;
|
||||
}
|
||||
bool psHasNativeNotifications();
|
||||
|
||||
virtual QImage iconWithCounter(int size, int count, style::color bg, bool smallIcon) = 0;
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
|||
#include "window/notifications_utilities.h"
|
||||
#include "platform/linux/linux_libnotify.h"
|
||||
#include "platform/linux/linux_libs.h"
|
||||
#include "lang.h"
|
||||
|
||||
namespace Platform {
|
||||
namespace Notifications {
|
||||
|
@ -31,7 +32,7 @@ namespace {
|
|||
|
||||
NeverFreedPointer<Manager> ManagerInstance;
|
||||
|
||||
bool supported() {
|
||||
bool LibNotifyLoaded() {
|
||||
return (Libs::notify_init != nullptr)
|
||||
&& (Libs::notify_uninit != nullptr)
|
||||
&& (Libs::notify_is_initted != nullptr)
|
||||
|
@ -43,7 +44,7 @@ bool supported() {
|
|||
&& (Libs::notify_notification_update != nullptr)
|
||||
&& (Libs::notify_notification_show != nullptr)
|
||||
// && (Libs::notify_notification_set_app_name != nullptr)
|
||||
// && (Libs::notify_notification_set_timeout != nullptr)
|
||||
&& (Libs::notify_notification_set_timeout != nullptr)
|
||||
// && (Libs::notify_notification_set_category != nullptr)
|
||||
// && (Libs::notify_notification_set_urgency != nullptr)
|
||||
// && (Libs::notify_notification_set_icon_from_pixbuf != nullptr)
|
||||
|
@ -52,23 +53,139 @@ bool supported() {
|
|||
// && (Libs::notify_notification_set_hint_int32 != nullptr)
|
||||
// && (Libs::notify_notification_set_hint_uint32 != nullptr)
|
||||
// && (Libs::notify_notification_set_hint_double != nullptr)
|
||||
// && (Libs::notify_notification_set_hint_string != nullptr)
|
||||
&& (Libs::notify_notification_set_hint_string != nullptr)
|
||||
// && (Libs::notify_notification_set_hint_byte != nullptr)
|
||||
// && (Libs::notify_notification_set_hint_byte_array != nullptr)
|
||||
// && (Libs::notify_notification_clear_hints != nullptr)
|
||||
// && (Libs::notify_notification_add_action != nullptr)
|
||||
// && (Libs::notify_notification_clear_actions != nullptr)
|
||||
&& (Libs::notify_notification_add_action != nullptr)
|
||||
&& (Libs::notify_notification_clear_actions != nullptr)
|
||||
&& (Libs::notify_notification_close != nullptr)
|
||||
&& (Libs::notify_notification_get_closed_reason != nullptr)
|
||||
&& (Libs::g_object_ref_sink != nullptr)
|
||||
&& (Libs::g_object_unref != nullptr)
|
||||
&& (Libs::g_list_free_full != nullptr)
|
||||
&& (Libs::g_error_free != nullptr)
|
||||
&& (Libs::g_signal_connect_data != nullptr)
|
||||
&& (Libs::g_signal_handler_disconnect != nullptr)
|
||||
// && (Libs::gdk_pixbuf_new_from_data != nullptr)
|
||||
&& (Libs::gdk_pixbuf_new_from_file != nullptr);
|
||||
}
|
||||
|
||||
QString escapeNotificationHtml(QString text) {
|
||||
text = text.replace(QChar('<'), qstr("<"));
|
||||
text = text.replace(QChar('>'), qstr(">"));
|
||||
text = text.replace(QChar('&'), qstr("&"));
|
||||
return text;
|
||||
}
|
||||
|
||||
class NotificationData {
|
||||
public:
|
||||
NotificationData(const QString &title, const QString &body, PeerId peerId, MsgId msgId)
|
||||
: _data(Libs::notify_notification_new(title.toUtf8().constData(), body.toUtf8().constData(), nullptr))
|
||||
, _peerId(peerId)
|
||||
, _msgId(msgId) {
|
||||
if (valid()) {
|
||||
init();
|
||||
}
|
||||
}
|
||||
bool valid() const {
|
||||
return (_data != nullptr);
|
||||
}
|
||||
NotificationData(const NotificationData &other) = delete;
|
||||
NotificationData &operator=(const NotificationData &other) = delete;
|
||||
NotificationData(NotificationData &&other) = delete;
|
||||
NotificationData &operator=(NotificationData &&other) = delete;
|
||||
|
||||
void setImage(const QString &imagePath) {
|
||||
auto imagePathNative = QFile::encodeName(imagePath);
|
||||
if (auto pixbuf = Libs::gdk_pixbuf_new_from_file(imagePathNative.constData(), nullptr)) {
|
||||
Libs::notify_notification_set_image_from_pixbuf(_data, pixbuf);
|
||||
Libs::g_object_unref(Libs::g_object_cast(pixbuf));
|
||||
}
|
||||
}
|
||||
bool show() {
|
||||
if (valid()) {
|
||||
GError *error = nullptr;
|
||||
Libs::notify_notification_show(_data, &error);
|
||||
if (!error) {
|
||||
return true;
|
||||
}
|
||||
|
||||
logError(error);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool close() {
|
||||
if (valid()) {
|
||||
GError *error = nullptr;
|
||||
Libs::notify_notification_close(_data, &error);
|
||||
if (!error) {
|
||||
return true;
|
||||
}
|
||||
|
||||
logError(error);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
~NotificationData() {
|
||||
if (valid()) {
|
||||
if (_handlerId > 0) {
|
||||
Libs::g_signal_handler_disconnect(Libs::g_object_cast(_data), _handlerId);
|
||||
}
|
||||
Libs::notify_notification_clear_actions(_data);
|
||||
Libs::g_object_unref(Libs::g_object_cast(_data));
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void init() {
|
||||
_handlerId = Libs::g_signal_connect_helper(Libs::g_object_cast(_data), "closed", G_CALLBACK(NotificationData::notificationClosed), this);
|
||||
Libs::notify_notification_set_timeout(_data, Libs::NOTIFY_EXPIRES_DEFAULT);
|
||||
|
||||
if (auto manager = ManagerInstance.data()) {
|
||||
if (manager->hasActionsSupport()) {
|
||||
Libs::notify_notification_add_action(_data, "default", lang(lng_context_reply_msg).toUtf8().constData(), NotificationData::notificationClicked, this, nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
void onClose() {
|
||||
if (auto manager = ManagerInstance.data()) {
|
||||
manager->clearNotification(_peerId, _msgId);
|
||||
}
|
||||
}
|
||||
void onClick() {
|
||||
if (auto manager = ManagerInstance.data()) {
|
||||
manager->notificationActivated(_peerId, _msgId);
|
||||
}
|
||||
}
|
||||
|
||||
void logError(GError *error) {
|
||||
LOG(("LibNotify Error: domain %1, code %2, message '%3'").arg(error->domain).arg(error->code).arg(QString::fromUtf8(error->message)));
|
||||
Libs::g_error_free(error);
|
||||
}
|
||||
|
||||
static void notificationClosed(Libs::NotifyNotification *notification, gpointer data) {
|
||||
static_cast<NotificationData*>(data)->onClose();
|
||||
}
|
||||
static void notificationClicked(Libs::NotifyNotification *notification, char *action, gpointer data) {
|
||||
static_cast<NotificationData*>(data)->onClick();
|
||||
}
|
||||
|
||||
Libs::NotifyNotification *_data = nullptr;
|
||||
PeerId _peerId = 0;
|
||||
MsgId _msgId = 0;
|
||||
gulong _handlerId = 0;
|
||||
|
||||
};
|
||||
|
||||
using Notification = QSharedPointer<NotificationData>;
|
||||
|
||||
} // namespace
|
||||
|
||||
void start() {
|
||||
if (supported()) {
|
||||
if (LibNotifyLoaded()) {
|
||||
if (Libs::notify_is_initted() || Libs::notify_init("Telegram Desktop")) {
|
||||
ManagerInstance.makeIfNull();
|
||||
}
|
||||
|
@ -76,7 +193,14 @@ void start() {
|
|||
}
|
||||
|
||||
Manager *manager() {
|
||||
return ManagerInstance.data();
|
||||
if (Global::NativeNotifications()) {
|
||||
return ManagerInstance.data();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool supported() {
|
||||
return ManagerInstance.data() != nullptr;
|
||||
}
|
||||
|
||||
void finish() {
|
||||
|
@ -88,131 +212,214 @@ void finish() {
|
|||
|
||||
class Manager::Impl {
|
||||
public:
|
||||
Impl();
|
||||
|
||||
void showNotification(PeerData *peer, MsgId msgId, const QString &title, const QString &subtitle, bool showUserpic, const QString &msg, bool showReplyButton);
|
||||
void clearAll();
|
||||
void clearFromHistory(History *history);
|
||||
void clearNotification(PeerId peerId, MsgId msgId);
|
||||
|
||||
bool hasPoorSupport() const {
|
||||
return _poorSupported;
|
||||
}
|
||||
bool hasActionsSupport() const {
|
||||
return _actionsSupported;
|
||||
}
|
||||
|
||||
private:
|
||||
static void notificationClosed(Libs::NotifyNotification *notification, gpointer data);
|
||||
void clearNotification(Libs::NotifyNotification *notification);
|
||||
void showNextNotification();
|
||||
|
||||
using Notifications = QMap<PeerId, QMap<MsgId, Libs::NotifyNotification*>>;
|
||||
struct QueuedNotification {
|
||||
PeerData *peer = nullptr;
|
||||
MsgId msgId = 0;
|
||||
QString title;
|
||||
QString body;
|
||||
bool showUserpic = false;
|
||||
};
|
||||
|
||||
using QueuedNotifications = QList<QueuedNotification>;
|
||||
QueuedNotifications _queuedNotifications;
|
||||
|
||||
using Notifications = QMap<PeerId, QMap<MsgId, Notification>>;
|
||||
Notifications _notifications;
|
||||
|
||||
using NotificationsData = QMap<Libs::NotifyNotification*, QPair<PeerId, MsgId>>;
|
||||
NotificationsData _notificationsData;
|
||||
|
||||
Window::Notifications::CachedUserpics _cachedUserpics;
|
||||
bool _actionsSupported = false;
|
||||
bool _poorSupported = true;
|
||||
|
||||
};
|
||||
|
||||
void Manager::Impl::notificationClosed(Libs::NotifyNotification *notification, gpointer data) {
|
||||
if (auto manager = ManagerInstance.data()) {
|
||||
manager->_impl->clearNotification(notification);
|
||||
}
|
||||
void FreeCapability(void *ptr, void *data) {
|
||||
Libs::g_free(ptr);
|
||||
}
|
||||
|
||||
void Manager::Impl::clearNotification(Libs::NotifyNotification *notification) {
|
||||
auto dataIt = _notificationsData.find(notification);
|
||||
if (dataIt == _notificationsData.cend()) {
|
||||
return;
|
||||
Manager::Impl::Impl() {
|
||||
if (auto capabilities = Libs::notify_get_server_caps()) {
|
||||
for (auto capability = capabilities; capability; capability = capability->next) {
|
||||
if (QString::fromUtf8(static_cast<const char*>(capability->data)) == qstr("actions")) {
|
||||
_actionsSupported = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
Libs::g_list_free_full(capabilities, g_free);
|
||||
Libs::g_list_free(capabilities);
|
||||
}
|
||||
|
||||
auto peerId = dataIt->first;
|
||||
auto msgId = dataIt->second;
|
||||
_notificationsData.erase(dataIt);
|
||||
|
||||
auto i = _notifications.find(peerId);
|
||||
if (i != _notifications.cend()) {
|
||||
auto it = i.value().find(msgId);
|
||||
if (it != i.value().cend()) {
|
||||
Libs::g_object_unref(Libs::g_object_cast(it.value()));
|
||||
i.value().erase(it);
|
||||
if (i.value().isEmpty()) {
|
||||
_notifications.erase(i);
|
||||
// Unity and other Notify OSD users handle desktop notifications
|
||||
// extremely poor, even without the ability to close() them.
|
||||
gchar *name = nullptr;
|
||||
if (Libs::notify_get_server_info(&name, nullptr, nullptr, nullptr)) {
|
||||
if (name) {
|
||||
auto serverName = QString::fromUtf8(static_cast<const char*>(name));
|
||||
LOG(("Notifications Server: %1").arg(serverName));
|
||||
if (serverName == qstr("notify-osd")) {
|
||||
_actionsSupported = false;
|
||||
}
|
||||
Libs::g_free(name);
|
||||
}
|
||||
}
|
||||
if (!_actionsSupported) {
|
||||
_poorSupported = true;
|
||||
}
|
||||
}
|
||||
|
||||
void Manager::Impl::showNotification(PeerData *peer, MsgId msgId, const QString &title, const QString &subtitle, bool showUserpic, const QString &msg, bool showReplyButton) {
|
||||
auto titleUtf8 = title.toUtf8();
|
||||
auto bodyUtf8 = (subtitle.isEmpty() ? msg : ("<b>" + subtitle + "</b>\n" + msg)).toUtf8();
|
||||
auto notification = Libs::notify_notification_new(titleUtf8.constData(), bodyUtf8.constData(), nullptr);
|
||||
if (!notification) {
|
||||
auto titleText = escapeNotificationHtml(title);
|
||||
auto bodyText = subtitle.isEmpty() ? escapeNotificationHtml(msg) : ("<b>" + escapeNotificationHtml(subtitle) + "</b>\n" + escapeNotificationHtml(msg));
|
||||
|
||||
QueuedNotification notification;
|
||||
notification.peer = peer;
|
||||
notification.msgId = msgId;
|
||||
notification.title = titleText;
|
||||
notification.body = bodyText;
|
||||
notification.showUserpic = showUserpic;
|
||||
_queuedNotifications.push_back(notification);
|
||||
|
||||
showNextNotification();
|
||||
}
|
||||
|
||||
void Manager::Impl::showNextNotification() {
|
||||
// Show only one notification at a time in Unity / Notify OSD.
|
||||
if (_poorSupported) {
|
||||
for (auto b = _notifications.begin(); !_notifications.isEmpty() && b->isEmpty();) {
|
||||
_notifications.erase(b);
|
||||
}
|
||||
if (!_notifications.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
QueuedNotification data;
|
||||
while (!_queuedNotifications.isEmpty()) {
|
||||
data = _queuedNotifications.front();
|
||||
_queuedNotifications.pop_front();
|
||||
if (data.peer) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!data.peer) {
|
||||
return;
|
||||
}
|
||||
|
||||
Libs::g_signal_connect_helper(Libs::g_object_cast(notification), "closed", G_CALLBACK(Manager::Impl::notificationClosed), peer);
|
||||
auto peerId = data.peer->id;
|
||||
auto msgId = data.msgId;
|
||||
auto notification = MakeShared<NotificationData>(data.title, data.body, peerId, msgId);
|
||||
if (!notification->valid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
StorageKey key;
|
||||
if (showUserpic) {
|
||||
key = peer->userpicUniqueKey();
|
||||
if (data.showUserpic) {
|
||||
key = data.peer->userpicUniqueKey();
|
||||
} else {
|
||||
key = StorageKey(0, 0);
|
||||
}
|
||||
auto userpicPath = _cachedUserpics.get(key, peer);
|
||||
auto userpicPathNative = QFile::encodeName(userpicPath);
|
||||
if (auto pixbuf = Libs::gdk_pixbuf_new_from_file(userpicPathNative.constData(), nullptr)) {
|
||||
Libs::notify_notification_set_image_from_pixbuf(notification, pixbuf);
|
||||
Libs::g_object_unref(Libs::g_object_cast(pixbuf));
|
||||
}
|
||||
notification->setImage(_cachedUserpics.get(key, data.peer));
|
||||
|
||||
auto i = _notifications.find(peer->id);
|
||||
auto i = _notifications.find(peerId);
|
||||
if (i != _notifications.cend()) {
|
||||
auto j = i->find(msgId);
|
||||
if (j != i->cend()) {
|
||||
auto oldNotification = j.value();
|
||||
i->erase(j);
|
||||
_notificationsData.remove(oldNotification);
|
||||
Libs::notify_notification_close(oldNotification, nullptr);
|
||||
Libs::g_object_unref(Libs::g_object_cast(oldNotification));
|
||||
i = _notifications.find(peer->id);
|
||||
oldNotification->close();
|
||||
i = _notifications.find(peerId);
|
||||
}
|
||||
}
|
||||
if (i == _notifications.cend()) {
|
||||
i = _notifications.insert(peer->id, QMap<MsgId, Libs::NotifyNotification*>());
|
||||
i = _notifications.insert(peerId, QMap<MsgId, Notification>());
|
||||
}
|
||||
auto result = Libs::notify_notification_show(notification, nullptr);
|
||||
if (!result) {
|
||||
Libs::g_object_unref(Libs::g_object_cast(notification));
|
||||
i = _notifications.find(peer->id);
|
||||
if (i != _notifications.cend() && i->isEmpty()) _notifications.erase(i);
|
||||
return;
|
||||
_notifications[peerId].insert(msgId, notification);
|
||||
if (!notification->show()) {
|
||||
i = _notifications.find(peerId);
|
||||
if (i != _notifications.cend()) {
|
||||
i->remove(msgId);
|
||||
if (i->isEmpty()) _notifications.erase(i);
|
||||
}
|
||||
showNextNotification();
|
||||
}
|
||||
_notifications[peer->id].insert(msgId, notification);
|
||||
_notificationsData.insert(notification, qMakePair(peer->id, msgId));
|
||||
}
|
||||
|
||||
void Manager::Impl::clearAll() {
|
||||
_notificationsData.clear();
|
||||
_queuedNotifications.clear();
|
||||
|
||||
auto temp = createAndSwap(_notifications);
|
||||
for_const (auto ¬ifications, temp) {
|
||||
for_const (auto notification, notifications) {
|
||||
Libs::notify_notification_close(notification, nullptr);
|
||||
Libs::g_object_unref(Libs::g_object_cast(notification));
|
||||
notification->close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Manager::Impl::clearFromHistory(History *history) {
|
||||
for (auto i = _queuedNotifications.begin(); i != _queuedNotifications.end();) {
|
||||
if (i->peer == history->peer) {
|
||||
i = _queuedNotifications.erase(i);
|
||||
} else {
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
auto i = _notifications.find(history->peer->id);
|
||||
if (i != _notifications.cend()) {
|
||||
auto temp = createAndSwap(i.value());
|
||||
_notifications.erase(i);
|
||||
|
||||
for_const (auto notification, temp) {
|
||||
_notificationsData.remove(notification);
|
||||
Libs::notify_notification_close(notification, nullptr);
|
||||
Libs::g_object_unref(Libs::g_object_cast(notification));
|
||||
notification->close();
|
||||
}
|
||||
}
|
||||
|
||||
showNextNotification();
|
||||
}
|
||||
|
||||
void Manager::Impl::clearNotification(PeerId peerId, MsgId msgId) {
|
||||
auto i = _notifications.find(peerId);
|
||||
if (i != _notifications.cend()) {
|
||||
i.value().remove(msgId);
|
||||
if (i.value().isEmpty()) {
|
||||
_notifications.erase(i);
|
||||
}
|
||||
}
|
||||
|
||||
showNextNotification();
|
||||
}
|
||||
|
||||
Manager::Manager() : _impl(std_::make_unique<Impl>()) {
|
||||
}
|
||||
|
||||
void Manager::clearNotification(PeerId peerId, MsgId msgId) {
|
||||
_impl->clearNotification(peerId, msgId);
|
||||
}
|
||||
|
||||
bool Manager::hasPoorSupport() const {
|
||||
return _impl->hasPoorSupport();
|
||||
}
|
||||
|
||||
bool Manager::hasActionsSupport() const {
|
||||
return _impl->hasActionsSupport();
|
||||
}
|
||||
|
||||
Manager::~Manager() = default;
|
||||
|
||||
void Manager::doShowNativeNotification(PeerData *peer, MsgId msgId, const QString &title, const QString &subtitle, bool showUserpic, const QString &msg, bool showReplyButton) {
|
||||
|
|
|
@ -29,6 +29,7 @@ class Manager;
|
|||
|
||||
void start();
|
||||
Manager *manager();
|
||||
bool supported();
|
||||
void finish();
|
||||
|
||||
inline void defaultNotificationShown(QWidget *widget) {
|
||||
|
@ -37,6 +38,11 @@ inline void defaultNotificationShown(QWidget *widget) {
|
|||
class Manager : public Window::Notifications::NativeManager {
|
||||
public:
|
||||
Manager();
|
||||
|
||||
void clearNotification(PeerId peerId, MsgId msgId);
|
||||
bool hasPoorSupport() const;
|
||||
bool hasActionsSupport() const;
|
||||
|
||||
~Manager();
|
||||
|
||||
protected:
|
||||
|
|
|
@ -21,7 +21,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
|||
#include "stdafx.h"
|
||||
#include "platform/win/main_window_win.h"
|
||||
|
||||
#include "platform/win/notifications_manager_win.h"
|
||||
#include "platform/platform_notifications_manager.h"
|
||||
#include "platform/win/windows_dlls.h"
|
||||
#include "window/notifications_manager.h"
|
||||
#include "mainwindow.h"
|
||||
|
|
|
@ -321,7 +321,7 @@ void start() {
|
|||
}
|
||||
|
||||
Manager *manager() {
|
||||
if (Global::WindowsNotifications()) {
|
||||
if (Global::NativeNotifications()) {
|
||||
return ManagerInstance.data();
|
||||
}
|
||||
return nullptr;
|
||||
|
|
|
@ -60,11 +60,20 @@ void NotificationsWidget::createControls() {
|
|||
}
|
||||
addChildRow(_playSound, margin, lang(lng_settings_sound_notify), SLOT(onPlaySound()), Global::SoundNotify());
|
||||
addChildRow(_includeMuted, margin, lang(lng_settings_include_muted), SLOT(onIncludeMuted()), Global::IncludeMuted());
|
||||
|
||||
QString nativeNotificationsLabel;
|
||||
#ifdef Q_OS_WIN
|
||||
if (App::wnd()->psHasNativeNotifications()) {
|
||||
addChildRow(_windowsNative, margin, lang(lng_settings_use_windows), SLOT(onWindowsNative()), Global::WindowsNotifications());
|
||||
nativeNotificationsLabel = lang(lng_settings_use_windows);
|
||||
}
|
||||
#elif defined Q_OS_LINUX64 || defined Q_OS_LINUX32
|
||||
if (App::wnd()->psHasNativeNotifications()) {
|
||||
nativeNotificationsLabel = lang(lng_settings_use_native_notifications);
|
||||
}
|
||||
#endif // Q_OS_WIN
|
||||
if (!nativeNotificationsLabel.isEmpty()) {
|
||||
addChildRow(_nativeNotifications, margin, nativeNotificationsLabel, SLOT(onNativeNotifications()), Global::NativeNotifications());
|
||||
}
|
||||
}
|
||||
|
||||
void NotificationsWidget::onDesktopNotifications() {
|
||||
|
@ -132,13 +141,13 @@ void NotificationsWidget::viewParamUpdated() {
|
|||
}
|
||||
}
|
||||
|
||||
void NotificationsWidget::onWindowsNative() {
|
||||
if (Global::WindowsNotifications() == _windowsNative->checked()) {
|
||||
void NotificationsWidget::onNativeNotifications() {
|
||||
if (Global::NativeNotifications() == _nativeNotifications->checked()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Window::Notifications::manager()->clearAllFast();
|
||||
Global::SetWindowsNotifications(_windowsNative->checked());
|
||||
Global::SetNativeNotifications(_nativeNotifications->checked());
|
||||
Local::writeUserSettings();
|
||||
}
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@ private slots:
|
|||
void onDesktopNotifications();
|
||||
void onShowSenderName();
|
||||
void onShowMessagePreview();
|
||||
void onWindowsNative();
|
||||
void onNativeNotifications();
|
||||
void onPlaySound();
|
||||
void onIncludeMuted();
|
||||
|
||||
|
@ -46,7 +46,7 @@ private:
|
|||
ChildWidget<Checkbox> _desktopNotifications = { nullptr };
|
||||
ChildWidget<Ui::WidgetSlideWrap<Checkbox>> _showSenderName = { nullptr };
|
||||
ChildWidget<Ui::WidgetSlideWrap<Checkbox>> _showMessagePreview = { nullptr };
|
||||
ChildWidget<Checkbox> _windowsNative = { nullptr };
|
||||
ChildWidget<Checkbox> _nativeNotifications = { nullptr };
|
||||
ChildWidget<Checkbox> _playSound = { nullptr };
|
||||
ChildWidget<Checkbox> _includeMuted = { nullptr };
|
||||
|
||||
|
|
Loading…
Reference in New Issue