mirror of
https://github.com/telegramdesktop/tdesktop
synced 2025-01-10 16:59:55 +00:00
LibNotify Linux notifications support added, testing.
This commit is contained in:
parent
2d1d62a953
commit
6db52f7fa9
@ -292,6 +292,10 @@ static const int32 ApiId = 17349;
|
||||
static const char *ApiHash = "344583e45741c457fe1862106095a5eb";
|
||||
#endif
|
||||
|
||||
#if Q_BYTE_ORDER == Q_BIG_ENDIAN
|
||||
#error "Only little endian is supported!"
|
||||
#endif // Q_BYTE_ORDER == Q_BIG_ENDIAN
|
||||
|
||||
#ifndef BETA_VERSION_MACRO
|
||||
#error "Beta version macro is not defined."
|
||||
#endif
|
||||
|
118
Telegram/SourceFiles/platform/linux/linux_libnotify.cpp
Normal file
118
Telegram/SourceFiles/platform/linux/linux_libnotify.cpp
Normal file
@ -0,0 +1,118 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop version of Telegram messaging app, see https://telegram.org
|
||||
|
||||
Telegram Desktop is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
It is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
In addition, as a special exception, the copyright holders give permission
|
||||
to link the code of portions of this program with the OpenSSL library.
|
||||
|
||||
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||
*/
|
||||
#include "stdafx.h"
|
||||
#include "platform/linux/linux_libnotify.h"
|
||||
|
||||
#include "platform/linux/linux_libs.h"
|
||||
|
||||
namespace Platform {
|
||||
namespace Libs {
|
||||
namespace {
|
||||
|
||||
bool loadLibrary(QLibrary &lib, const char *name, int version) {
|
||||
DEBUG_LOG(("Loading '%1' with version %2...").arg(QLatin1String(name)).arg(version));
|
||||
lib.setFileNameAndVersion(QLatin1String(name), version);
|
||||
if (lib.load()) {
|
||||
DEBUG_LOG(("Loaded '%1' with version %2!").arg(QLatin1String(name)).arg(version));
|
||||
return true;
|
||||
}
|
||||
lib.setFileNameAndVersion(QLatin1String(name), QString());
|
||||
if (lib.load()) {
|
||||
DEBUG_LOG(("Loaded '%1' without version!").arg(QLatin1String(name)));
|
||||
return true;
|
||||
}
|
||||
LOG(("Could not load '%1' with version %2 :(").arg(QLatin1String(name)).arg(version));
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
f_notify_init notify_init = nullptr;
|
||||
f_notify_uninit notify_uninit = nullptr;
|
||||
f_notify_is_initted notify_is_initted = nullptr;
|
||||
f_notify_get_app_name notify_get_app_name = nullptr;
|
||||
f_notify_set_app_name notify_set_app_name = nullptr;
|
||||
f_notify_get_server_caps notify_get_server_caps = nullptr;
|
||||
f_notify_get_server_info notify_get_server_info = nullptr;
|
||||
|
||||
f_notify_notification_new notify_notification_new = nullptr;
|
||||
f_notify_notification_update notify_notification_update = nullptr;
|
||||
f_notify_notification_show notify_notification_show = nullptr;
|
||||
f_notify_notification_set_app_name notify_notification_set_app_name = nullptr;
|
||||
f_notify_notification_set_timeout notify_notification_set_timeout = nullptr;
|
||||
f_notify_notification_set_category notify_notification_set_category = nullptr;
|
||||
f_notify_notification_set_urgency notify_notification_set_urgency = nullptr;
|
||||
f_notify_notification_set_icon_from_pixbuf notify_notification_set_icon_from_pixbuf = nullptr;
|
||||
f_notify_notification_set_image_from_pixbuf notify_notification_set_image_from_pixbuf = nullptr;
|
||||
f_notify_notification_set_hint notify_notification_set_hint = nullptr;
|
||||
f_notify_notification_set_hint_int32 notify_notification_set_hint_int32 = nullptr;
|
||||
f_notify_notification_set_hint_uint32 notify_notification_set_hint_uint32 = nullptr;
|
||||
f_notify_notification_set_hint_double notify_notification_set_hint_double = nullptr;
|
||||
f_notify_notification_set_hint_string notify_notification_set_hint_string = nullptr;
|
||||
f_notify_notification_set_hint_byte notify_notification_set_hint_byte = nullptr;
|
||||
f_notify_notification_set_hint_byte_array notify_notification_set_hint_byte_array = nullptr;
|
||||
f_notify_notification_clear_hints notify_notification_clear_hints = nullptr;
|
||||
f_notify_notification_add_action notify_notification_add_action = nullptr;
|
||||
f_notify_notification_clear_actions notify_notification_clear_actions = nullptr;
|
||||
f_notify_notification_close notify_notification_close = nullptr;
|
||||
f_notify_notification_get_closed_reason notify_notification_get_closed_reason = nullptr;
|
||||
|
||||
void startLibNotify() {
|
||||
DEBUG_LOG(("Loading libnotify"));
|
||||
|
||||
QLibrary lib_notify;
|
||||
if (!loadLibrary(lib_notify, "notify", 4)) {
|
||||
return;
|
||||
}
|
||||
|
||||
load(lib_notify, "notify_init", notify_init);
|
||||
load(lib_notify, "notify_uninit", notify_uninit);
|
||||
load(lib_notify, "notify_is_initted", notify_is_initted);
|
||||
load(lib_notify, "notify_get_app_name", notify_get_app_name);
|
||||
load(lib_notify, "notify_set_app_name", notify_set_app_name);
|
||||
load(lib_notify, "notify_get_server_caps", notify_get_server_caps);
|
||||
load(lib_notify, "notify_get_server_info", notify_get_server_info);
|
||||
|
||||
load(lib_notify, "notify_notification_new", notify_notification_new);
|
||||
load(lib_notify, "notify_notification_update", notify_notification_update);
|
||||
load(lib_notify, "notify_notification_show", notify_notification_show);
|
||||
load(lib_notify, "notify_notification_set_app_name", notify_notification_set_app_name);
|
||||
load(lib_notify, "notify_notification_set_timeout", notify_notification_set_timeout);
|
||||
load(lib_notify, "notify_notification_set_category", notify_notification_set_category);
|
||||
load(lib_notify, "notify_notification_set_urgency", notify_notification_set_urgency);
|
||||
load(lib_notify, "notify_notification_set_icon_from_pixbuf", notify_notification_set_icon_from_pixbuf);
|
||||
load(lib_notify, "notify_notification_set_image_from_pixbuf", notify_notification_set_image_from_pixbuf);
|
||||
load(lib_notify, "notify_notification_set_hint", notify_notification_set_hint);
|
||||
load(lib_notify, "notify_notification_set_hint_int32", notify_notification_set_hint_int32);
|
||||
load(lib_notify, "notify_notification_set_hint_uint32", notify_notification_set_hint_uint32);
|
||||
load(lib_notify, "notify_notification_set_hint_double", notify_notification_set_hint_double);
|
||||
load(lib_notify, "notify_notification_set_hint_string", notify_notification_set_hint_string);
|
||||
load(lib_notify, "notify_notification_set_hint_byte", notify_notification_set_hint_byte);
|
||||
load(lib_notify, "notify_notification_set_hint_byte_array", notify_notification_set_hint_byte_array);
|
||||
load(lib_notify, "notify_notification_clear_hints", notify_notification_clear_hints);
|
||||
load(lib_notify, "notify_notification_add_action", notify_notification_add_action);
|
||||
load(lib_notify, "notify_notification_clear_actions", notify_notification_clear_actions);
|
||||
load(lib_notify, "notify_notification_close", notify_notification_close);
|
||||
load(lib_notify, "notify_notification_get_closed_reason", notify_notification_get_closed_reason);
|
||||
}
|
||||
|
||||
} // namespace Libs
|
||||
} // namespace Platform
|
131
Telegram/SourceFiles/platform/linux/linux_libnotify.h
Normal file
131
Telegram/SourceFiles/platform/linux/linux_libnotify.h
Normal file
@ -0,0 +1,131 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop version of Telegram messaging app, see https://telegram.org
|
||||
|
||||
Telegram Desktop is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
It is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
In addition, as a special exception, the copyright holders give permission
|
||||
to link the code of portions of this program with the OpenSSL library.
|
||||
|
||||
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
extern "C" {
|
||||
#undef signals
|
||||
#include <gtk/gtk.h>
|
||||
#define signals public
|
||||
} // extern "C"
|
||||
|
||||
namespace Platform {
|
||||
namespace Libs {
|
||||
|
||||
void startLibNotify();
|
||||
|
||||
constexpr gint NOTIFY_EXPIRES_DEFAULT = -1;
|
||||
constexpr gint NOTIFY_EXPIRES_NEVER = 0;
|
||||
|
||||
struct NotifyNotification;
|
||||
typedef enum {
|
||||
NOTIFY_URGENCY_LOW,
|
||||
NOTIFY_URGENCY_NORMAL,
|
||||
NOTIFY_URGENCY_CRITICAL,
|
||||
} NotifyUrgency;
|
||||
|
||||
using NotifyActionCallback = void (*)(NotifyNotification *notification, char *action, gpointer user_data);
|
||||
|
||||
using f_notify_init = gboolean (*)(const char *app_name);
|
||||
extern f_notify_init notify_init;
|
||||
|
||||
using f_notify_uninit = void (*)(void);
|
||||
extern f_notify_uninit notify_uninit;
|
||||
|
||||
using f_notify_is_initted = gboolean (*)(void);
|
||||
extern f_notify_is_initted notify_is_initted;
|
||||
|
||||
using f_notify_get_app_name = const char* (*)(void);
|
||||
extern f_notify_get_app_name notify_get_app_name;
|
||||
|
||||
using f_notify_set_app_name = void (*)(const char *app_name);
|
||||
extern f_notify_set_app_name notify_set_app_name;
|
||||
|
||||
using f_notify_get_server_caps = GList* (*)(void);
|
||||
extern f_notify_get_server_caps notify_get_server_caps;
|
||||
|
||||
using f_notify_get_server_info = gboolean (*)(char **ret_name, char **ret_vendor, char **ret_version, char **ret_spec_version);
|
||||
extern f_notify_get_server_info notify_get_server_info;
|
||||
|
||||
using f_notify_notification_new = NotifyNotification* (*)(const char *summary, const char *body, const char *icon);
|
||||
extern f_notify_notification_new notify_notification_new;
|
||||
|
||||
using f_notify_notification_update = gboolean (*)(NotifyNotification *notification, const char *summary, const char *body, const char *icon);
|
||||
extern f_notify_notification_update notify_notification_update;
|
||||
|
||||
using f_notify_notification_show = gboolean (*)(NotifyNotification *notification, GError **error);
|
||||
extern f_notify_notification_show notify_notification_show;
|
||||
|
||||
using f_notify_notification_set_app_name = void (*)(NotifyNotification *notification, const char *app_name);
|
||||
extern f_notify_notification_set_app_name notify_notification_set_app_name;
|
||||
|
||||
using f_notify_notification_set_timeout = void (*)(NotifyNotification *notification, gint timeout);
|
||||
extern f_notify_notification_set_timeout notify_notification_set_timeout;
|
||||
|
||||
using f_notify_notification_set_category = void (*)(NotifyNotification *notification, const char *category);
|
||||
extern f_notify_notification_set_category notify_notification_set_category;
|
||||
|
||||
using f_notify_notification_set_urgency = void (*)(NotifyNotification *notification, NotifyUrgency urgency);
|
||||
extern f_notify_notification_set_urgency notify_notification_set_urgency;
|
||||
|
||||
using f_notify_notification_set_icon_from_pixbuf = void (*)(NotifyNotification *notification, GdkPixbuf *icon);
|
||||
extern f_notify_notification_set_icon_from_pixbuf notify_notification_set_icon_from_pixbuf;
|
||||
|
||||
using f_notify_notification_set_image_from_pixbuf = void (*)(NotifyNotification *notification, GdkPixbuf *pixbuf);
|
||||
extern f_notify_notification_set_image_from_pixbuf notify_notification_set_image_from_pixbuf;
|
||||
|
||||
using f_notify_notification_set_hint = void (*)(NotifyNotification *notification, const char *key, GVariant *value);
|
||||
extern f_notify_notification_set_hint notify_notification_set_hint;
|
||||
|
||||
using f_notify_notification_set_hint_int32 = void (*)(NotifyNotification *notification, const char *key, gint value);
|
||||
extern f_notify_notification_set_hint_int32 notify_notification_set_hint_int32;
|
||||
|
||||
using f_notify_notification_set_hint_uint32 = void (*)(NotifyNotification *notification, const char *key, guint value);
|
||||
extern f_notify_notification_set_hint_uint32 notify_notification_set_hint_uint32;
|
||||
|
||||
using f_notify_notification_set_hint_double = void (*)(NotifyNotification *notification, const char *key, gdouble value);
|
||||
extern f_notify_notification_set_hint_double notify_notification_set_hint_double;
|
||||
|
||||
using f_notify_notification_set_hint_string = void (*)(NotifyNotification *notification, const char *key, const char *value);
|
||||
extern f_notify_notification_set_hint_string notify_notification_set_hint_string;
|
||||
|
||||
using f_notify_notification_set_hint_byte = void (*)(NotifyNotification *notification, const char *key, guchar value);
|
||||
extern f_notify_notification_set_hint_byte notify_notification_set_hint_byte;
|
||||
|
||||
using f_notify_notification_set_hint_byte_array = void (*)(NotifyNotification *notification, const char *key, const guchar *value, gsize len);
|
||||
extern f_notify_notification_set_hint_byte_array notify_notification_set_hint_byte_array;
|
||||
|
||||
using f_notify_notification_clear_hints = void (*)(NotifyNotification *notification);
|
||||
extern f_notify_notification_clear_hints notify_notification_clear_hints;
|
||||
|
||||
using f_notify_notification_add_action = void (*)(NotifyNotification *notification, const char *action, const char *label, NotifyActionCallback callback, gpointer user_data, GFreeFunc free_func);
|
||||
extern f_notify_notification_add_action notify_notification_add_action;
|
||||
|
||||
using f_notify_notification_clear_actions = void (*)(NotifyNotification *notification);
|
||||
extern f_notify_notification_clear_actions notify_notification_clear_actions;
|
||||
|
||||
using f_notify_notification_close = gboolean (*)(NotifyNotification *notification, GError **error);
|
||||
extern f_notify_notification_close notify_notification_close;
|
||||
|
||||
using f_notify_notification_get_closed_reason = gint (*)(const NotifyNotification *notification);
|
||||
extern f_notify_notification_get_closed_reason notify_notification_get_closed_reason;
|
||||
|
||||
} // namespace Libs
|
||||
} // namespace Platform
|
@ -22,6 +22,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||
#include "platform/linux/linux_libs.h"
|
||||
|
||||
#include "platform/linux/linux_gdk_helper.h"
|
||||
#include "platform/linux/linux_libnotify.h"
|
||||
|
||||
namespace Platform {
|
||||
namespace Libs {
|
||||
@ -175,6 +176,7 @@ f_app_indicator_set_menu app_indicator_set_menu = nullptr;
|
||||
f_app_indicator_set_icon_full app_indicator_set_icon_full = nullptr;
|
||||
f_gdk_init_check gdk_init_check = nullptr;
|
||||
f_gdk_pixbuf_new_from_data gdk_pixbuf_new_from_data = nullptr;
|
||||
f_gdk_pixbuf_new_from_file gdk_pixbuf_new_from_file = nullptr;
|
||||
f_gtk_status_icon_new_from_pixbuf gtk_status_icon_new_from_pixbuf = nullptr;
|
||||
f_gtk_status_icon_set_from_pixbuf gtk_status_icon_set_from_pixbuf = nullptr;
|
||||
f_gtk_status_icon_new_from_file gtk_status_icon_new_from_file = nullptr;
|
||||
@ -233,6 +235,7 @@ void start() {
|
||||
if (gtkLoaded) {
|
||||
load(lib_gtk, "gdk_init_check", gdk_init_check);
|
||||
load(lib_gtk, "gdk_pixbuf_new_from_data", gdk_pixbuf_new_from_data);
|
||||
load(lib_gtk, "gdk_pixbuf_new_from_file", gdk_pixbuf_new_from_file);
|
||||
load(lib_gtk, "gtk_status_icon_new_from_pixbuf", gtk_status_icon_new_from_pixbuf);
|
||||
load(lib_gtk, "gtk_status_icon_set_from_pixbuf", gtk_status_icon_set_from_pixbuf);
|
||||
load(lib_gtk, "gtk_status_icon_new_from_file", gtk_status_icon_new_from_file);
|
||||
@ -266,6 +269,10 @@ void start() {
|
||||
load(lib_unity, "unity_launcher_entry_set_count_visible", unity_launcher_entry_set_count_visible);
|
||||
}
|
||||
#endif // TDESKTOP_DISABLE_UNITY_INTEGRATION
|
||||
|
||||
if (gtkLoaded) {
|
||||
startLibNotify();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Libs
|
||||
|
@ -273,6 +273,9 @@ extern f_gdk_init_check gdk_init_check;
|
||||
typedef GdkPixbuf* (*f_gdk_pixbuf_new_from_data)(const guchar *data, GdkColorspace colorspace, gboolean has_alpha, int bits_per_sample, int width, int height, int rowstride, GdkPixbufDestroyNotify destroy_fn, gpointer destroy_fn_data);
|
||||
extern f_gdk_pixbuf_new_from_data gdk_pixbuf_new_from_data;
|
||||
|
||||
typedef GdkPixbuf* (*f_gdk_pixbuf_new_from_file)(const gchar *filename, GError **error);
|
||||
extern f_gdk_pixbuf_new_from_file gdk_pixbuf_new_from_file;
|
||||
|
||||
typedef GtkStatusIcon* (*f_gtk_status_icon_new_from_pixbuf)(GdkPixbuf *pixbuf);
|
||||
extern f_gtk_status_icon_new_from_pixbuf gtk_status_icon_new_from_pixbuf;
|
||||
|
||||
|
@ -63,22 +63,11 @@ gboolean _trayIconResized(GtkStatusIcon *status_icon, gint size, gpointer popup_
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
#if Q_BYTE_ORDER == Q_BIG_ENDIAN
|
||||
|
||||
#define QT_RED 3
|
||||
#define QT_GREEN 2
|
||||
#define QT_BLUE 1
|
||||
#define QT_ALPHA 0
|
||||
|
||||
#else
|
||||
|
||||
#define QT_RED 0
|
||||
#define QT_GREEN 1
|
||||
#define QT_BLUE 2
|
||||
#define QT_ALPHA 3
|
||||
|
||||
#endif
|
||||
|
||||
#define GTK_RED 2
|
||||
#define GTK_GREEN 1
|
||||
#define GTK_BLUE 0
|
||||
|
@ -21,17 +21,210 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||
#include "stdafx.h"
|
||||
#include "platform/linux/notifications_manager_linux.h"
|
||||
|
||||
#include "window/notifications_utilities.h"
|
||||
#include "platform/linux/linux_libnotify.h"
|
||||
#include "platform/linux/linux_libs.h"
|
||||
|
||||
namespace Platform {
|
||||
namespace Notifications {
|
||||
namespace {
|
||||
|
||||
void start() {
|
||||
NeverFreedPointer<Manager> ManagerInstance;
|
||||
|
||||
bool supported() {
|
||||
return (Libs::notify_init != nullptr)
|
||||
&& (Libs::notify_uninit != nullptr)
|
||||
&& (Libs::notify_is_initted != nullptr)
|
||||
// && (Libs::notify_get_app_name != nullptr)
|
||||
// && (Libs::notify_set_app_name != nullptr)
|
||||
&& (Libs::notify_get_server_caps != nullptr)
|
||||
&& (Libs::notify_get_server_info != nullptr)
|
||||
&& (Libs::notify_notification_new != nullptr)
|
||||
&& (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_category != nullptr)
|
||||
// && (Libs::notify_notification_set_urgency != nullptr)
|
||||
// && (Libs::notify_notification_set_icon_from_pixbuf != nullptr)
|
||||
&& (Libs::notify_notification_set_image_from_pixbuf != nullptr)
|
||||
// && (Libs::notify_notification_set_hint != nullptr)
|
||||
// && (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_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_close != nullptr)
|
||||
&& (Libs::notify_notification_get_closed_reason != nullptr)
|
||||
&& (Libs::g_object_unref != nullptr)
|
||||
// && (Libs::gdk_pixbuf_new_from_data != nullptr)
|
||||
&& (Libs::gdk_pixbuf_new_from_file != nullptr);
|
||||
}
|
||||
|
||||
Window::Notifications::Manager *manager() {
|
||||
return nullptr;
|
||||
} // namespace
|
||||
|
||||
void start() {
|
||||
if (supported()) {
|
||||
if (Libs::notify_is_initted() || Libs::notify_init("Telegram Desktop")) {
|
||||
ManagerInstance.makeIfNull();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Manager *manager() {
|
||||
return ManagerInstance.data();
|
||||
}
|
||||
|
||||
void finish() {
|
||||
if (manager()) {
|
||||
ManagerInstance.reset();
|
||||
Libs::notify_uninit();
|
||||
}
|
||||
}
|
||||
|
||||
class Manager::Impl {
|
||||
public:
|
||||
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);
|
||||
|
||||
private:
|
||||
static void notificationClosed(Libs::NotifyNotification *notification, gpointer data);
|
||||
void clearNotification(Libs::NotifyNotification *notification);
|
||||
|
||||
using Notifications = QMap<PeerId, QMap<MsgId, Libs::NotifyNotification*>>;
|
||||
Notifications _notifications;
|
||||
|
||||
using NotificationsData = QMap<Libs::NotifyNotification*, QPair<PeerId, MsgId>>;
|
||||
NotificationsData _notificationsData;
|
||||
|
||||
Window::Notifications::CachedUserpics _cachedUserpics;
|
||||
|
||||
};
|
||||
|
||||
void Manager::Impl::notificationClosed(Libs::NotifyNotification *notification, gpointer data) {
|
||||
if (auto manager = ManagerInstance.data()) {
|
||||
manager->_impl->clearNotification(notification);
|
||||
}
|
||||
}
|
||||
|
||||
void Manager::Impl::clearNotification(Libs::NotifyNotification *notification) {
|
||||
auto dataIt = _notificationsData.find(notification);
|
||||
if (dataIt == _notificationsData.cend()) {
|
||||
return;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
return;
|
||||
}
|
||||
|
||||
Libs::g_signal_connect_helper(Libs::g_object_cast(notification), "closed", G_CALLBACK(Manager::Impl::notificationClosed), peer);
|
||||
|
||||
StorageKey key;
|
||||
if (showUserpic) {
|
||||
key = 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));
|
||||
}
|
||||
|
||||
auto i = _notifications.find(peer->id);
|
||||
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);
|
||||
}
|
||||
}
|
||||
if (i == _notifications.cend()) {
|
||||
i = _notifications.insert(peer->id, QMap<MsgId, Libs::NotifyNotification*>());
|
||||
}
|
||||
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[peer->id].insert(msgId, notification);
|
||||
_notificationsData.insert(notification, qMakePair(peer->id, msgId));
|
||||
}
|
||||
|
||||
void Manager::Impl::clearAll() {
|
||||
_notificationsData.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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Manager::Impl::clearFromHistory(History *history) {
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Manager::Manager() : _impl(std_::make_unique<Impl>()) {
|
||||
}
|
||||
|
||||
Manager::~Manager() = default;
|
||||
|
||||
void Manager::doShowNativeNotification(PeerData *peer, MsgId msgId, const QString &title, const QString &subtitle, bool showUserpic, const QString &msg, bool showReplyButton) {
|
||||
_impl->showNotification(peer, msgId, title, subtitle, showUserpic, msg, showReplyButton);
|
||||
}
|
||||
|
||||
void Manager::doClearAllFast() {
|
||||
_impl->clearAll();
|
||||
}
|
||||
|
||||
void Manager::doClearFromHistory(History *history) {
|
||||
_impl->clearFromHistory(history);
|
||||
}
|
||||
|
||||
} // namespace Notifications
|
||||
|
@ -25,12 +25,31 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||
namespace Platform {
|
||||
namespace Notifications {
|
||||
|
||||
class Manager;
|
||||
|
||||
void start();
|
||||
Window::Notifications::Manager *manager();
|
||||
Manager *manager();
|
||||
void finish();
|
||||
|
||||
inline void defaultNotificationShown(QWidget *widget) {
|
||||
}
|
||||
|
||||
class Manager : public Window::Notifications::NativeManager {
|
||||
public:
|
||||
Manager();
|
||||
~Manager();
|
||||
|
||||
protected:
|
||||
void doShowNativeNotification(PeerData *peer, MsgId msgId, const QString &title, const QString &subtitle, bool showUserpic, const QString &msg, bool showReplyButton) override;
|
||||
void doClearAllFast() override;
|
||||
void doClearFromHistory(History *history) override;
|
||||
|
||||
private:
|
||||
class Impl;
|
||||
friend class Impl;
|
||||
std_::unique_ptr<Impl> _impl;
|
||||
|
||||
};
|
||||
|
||||
} // namespace Notifications
|
||||
} // namespace Platform
|
||||
|
@ -21,6 +21,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||
#include "stdafx.h"
|
||||
#include "platform/win/notifications_manager_win.h"
|
||||
|
||||
#include "window/notifications_utilities.h"
|
||||
#include "platform/win/windows_app_user_model_id.h"
|
||||
#include "platform/win/windows_dlls.h"
|
||||
#include "mainwindow.h"
|
||||
@ -47,9 +48,6 @@ namespace Platform {
|
||||
namespace Notifications {
|
||||
namespace {
|
||||
|
||||
// Delete notify photo file after 1 minute of not using.
|
||||
constexpr int kNotifyDeletePhotoAfterMs = 60000;
|
||||
|
||||
NeverFreedPointer<Manager> ManagerInstance;
|
||||
|
||||
ComPtr<IToastNotificationManagerStatics> _notificationManager;
|
||||
@ -65,13 +63,6 @@ struct NotificationPtr {
|
||||
};
|
||||
using Notifications = QMap<PeerId, QMap<MsgId, NotificationPtr>>;
|
||||
Notifications _notifications;
|
||||
struct Image {
|
||||
uint64 until;
|
||||
QString path;
|
||||
};
|
||||
using Images = QMap<StorageKey, Image>;
|
||||
Images _images;
|
||||
bool _imageSavedFlag = false;
|
||||
|
||||
class StringReferenceWrapper {
|
||||
public:
|
||||
@ -155,7 +146,6 @@ bool init() {
|
||||
if (!SUCCEEDED(wrap_GetActivationFactory(StringReferenceWrapper(RuntimeClass_Windows_UI_Notifications_ToastNotification).Get(), &_notificationFactory))) {
|
||||
return false;
|
||||
}
|
||||
QDir().mkpath(cWorkingDir() + qsl("tdata/temp"));
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -322,38 +312,6 @@ private:
|
||||
|
||||
};
|
||||
|
||||
QString getImage(const StorageKey &key, PeerData *peer) {
|
||||
uint64 ms = getms(true);
|
||||
auto i = _images.find(key);
|
||||
if (i != _images.cend()) {
|
||||
if (i->until) {
|
||||
i->until = ms + kNotifyDeletePhotoAfterMs;
|
||||
if (auto manager = ManagerInstance.data()) {
|
||||
manager->clearPhotosInMs(-kNotifyDeletePhotoAfterMs);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Image v;
|
||||
if (key.first) {
|
||||
v.until = ms + kNotifyDeletePhotoAfterMs;
|
||||
if (auto manager = ManagerInstance.data()) {
|
||||
manager->clearPhotosInMs(-kNotifyDeletePhotoAfterMs);
|
||||
}
|
||||
} else {
|
||||
v.until = 0;
|
||||
}
|
||||
v.path = cWorkingDir() + qsl("tdata/temp/") + QString::number(rand_value<uint64>(), 16) + qsl(".png");
|
||||
if (key.first || key.second) {
|
||||
peer->saveUserpic(v.path, st::notifyMacPhotoSize);
|
||||
} else {
|
||||
App::wnd()->iconLarge().save(v.path, "PNG");
|
||||
}
|
||||
i = _images.insert(key, v);
|
||||
_imageSavedFlag = true;
|
||||
}
|
||||
return i->path;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void start() {
|
||||
@ -377,28 +335,6 @@ void finish() {
|
||||
ManagerInstance.clear();
|
||||
}
|
||||
|
||||
uint64 clearImages(uint64 ms) {
|
||||
uint64 result = 0;
|
||||
for (auto i = _images.begin(); i != _images.end();) {
|
||||
if (!i->until) {
|
||||
++i;
|
||||
continue;
|
||||
}
|
||||
if (i->until <= ms) {
|
||||
QFile(i->path).remove();
|
||||
i = _images.erase(i);
|
||||
} else {
|
||||
if (!result) {
|
||||
result = i->until;
|
||||
} else {
|
||||
accumulate_min(result, i->until);
|
||||
}
|
||||
++i;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
class Manager::Impl {
|
||||
public:
|
||||
bool showNotification(PeerData *peer, MsgId msgId, const QString &title, const QString &subtitle, bool showUserpic, const QString &msg, bool showReplyButton);
|
||||
@ -411,8 +347,7 @@ public:
|
||||
~Impl();
|
||||
|
||||
private:
|
||||
QTimer _clearPhotosTimer;
|
||||
friend class Manager;
|
||||
Window::Notifications::CachedUserpics _cachedUserpics;
|
||||
|
||||
};
|
||||
|
||||
@ -421,10 +356,6 @@ Manager::Impl::~Impl() {
|
||||
if (_notificationManager) _notificationManager.Reset();
|
||||
if (_notifier) _notifier.Reset();
|
||||
if (_notificationFactory) _notificationFactory.Reset();
|
||||
|
||||
if (_imageSavedFlag) {
|
||||
psDeleteDir(cWorkingDir() + qsl("tdata/temp"));
|
||||
}
|
||||
}
|
||||
|
||||
void Manager::Impl::clearAll() {
|
||||
@ -446,8 +377,8 @@ void Manager::Impl::clearFromHistory(History *history) {
|
||||
auto temp = createAndSwap(i.value());
|
||||
_notifications.erase(i);
|
||||
|
||||
for (auto j = temp.cbegin(), e = temp.cend(); j != e; ++j) {
|
||||
_notifier->Hide(j->p.Get());
|
||||
for_const (auto ¬ification, temp) {
|
||||
_notifier->Hide(notification.p.Get());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -485,16 +416,15 @@ bool Manager::Impl::showNotification(PeerData *peer, MsgId msgId, const QString
|
||||
if (!SUCCEEDED(hr)) return false;
|
||||
|
||||
StorageKey key;
|
||||
QString imagePath;
|
||||
if (showUserpic) {
|
||||
key = peer->userpicUniqueKey();
|
||||
} else {
|
||||
key = StorageKey(0, 0);
|
||||
}
|
||||
QString image = getImage(key, peer);
|
||||
std::wstring wimage = QDir::toNativeSeparators(image).toStdWString();
|
||||
auto userpicPath = _cachedUserpics.get(key, peer);
|
||||
auto userpicPathWide = QDir::toNativeSeparators(userpicPath).toStdWString();
|
||||
|
||||
hr = SetImageSrc(wimage.c_str(), toastXml.Get());
|
||||
hr = SetImageSrc(userpicPathWide.c_str(), toastXml.Get());
|
||||
if (!SUCCEEDED(hr)) return false;
|
||||
|
||||
ComPtr<IXmlNodeList> nodeList;
|
||||
@ -576,31 +506,12 @@ bool Manager::Impl::showNotification(PeerData *peer, MsgId msgId, const QString
|
||||
}
|
||||
|
||||
Manager::Manager() : _impl(std_::make_unique<Impl>()) {
|
||||
connect(&_impl->_clearPhotosTimer, SIGNAL(timeout()), this, SLOT(onClearPhotos()));
|
||||
}
|
||||
|
||||
void Manager::clearPhotosInMs(int ms) {
|
||||
if (ms < 0) {
|
||||
ms = -ms;
|
||||
if (_impl->_clearPhotosTimer.isActive() && _impl->_clearPhotosTimer.remainingTime() <= ms) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
_impl->_clearPhotosTimer.start(ms);
|
||||
}
|
||||
|
||||
void Manager::clearNotification(PeerId peerId, MsgId msgId) {
|
||||
_impl->clearNotification(peerId, msgId);
|
||||
}
|
||||
|
||||
void Manager::onClearPhotos() {
|
||||
auto ms = getms(true);
|
||||
auto minuntil = clearImages(ms);
|
||||
if (minuntil) {
|
||||
clearPhotosInMs(int32(minuntil - ms));
|
||||
}
|
||||
}
|
||||
|
||||
Manager::~Manager() = default;
|
||||
|
||||
void Manager::doShowNativeNotification(PeerData *peer, MsgId msgId, const QString &title, const QString &subtitle, bool showUserpic, const QString &msg, bool showReplyButton) {
|
||||
|
@ -35,20 +35,14 @@ void finish();
|
||||
inline void defaultNotificationShown(QWidget *widget) {
|
||||
}
|
||||
|
||||
class Manager : public QObject, public Window::Notifications::NativeManager {
|
||||
Q_OBJECT
|
||||
|
||||
class Manager : public Window::Notifications::NativeManager {
|
||||
public:
|
||||
Manager();
|
||||
|
||||
void clearPhotosInMs(int ms);
|
||||
void clearNotification(PeerId peerId, MsgId msgId);
|
||||
|
||||
~Manager();
|
||||
|
||||
private slots:
|
||||
void onClearPhotos();
|
||||
|
||||
protected:
|
||||
void doShowNativeNotification(PeerData *peer, MsgId msgId, const QString &title, const QString &subtitle, bool showUserpic, const QString &msg, bool showReplyButton) override;
|
||||
void doClearAllFast() override;
|
||||
|
116
Telegram/SourceFiles/window/notifications_utilities.cpp
Normal file
116
Telegram/SourceFiles/window/notifications_utilities.cpp
Normal file
@ -0,0 +1,116 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop version of Telegram messaging app, see https://telegram.org
|
||||
|
||||
Telegram Desktop is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
It is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
In addition, as a special exception, the copyright holders give permission
|
||||
to link the code of portions of this program with the OpenSSL library.
|
||||
|
||||
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||
*/
|
||||
#include "stdafx.h"
|
||||
#include "window/notifications_utilities.h"
|
||||
|
||||
#include "pspecific.h"
|
||||
#include "mainwindow.h"
|
||||
|
||||
namespace Window {
|
||||
namespace Notifications {
|
||||
namespace {
|
||||
|
||||
// Delete notify photo file after 1 minute of not using.
|
||||
constexpr int kNotifyDeletePhotoAfterMs = 60000;
|
||||
|
||||
} // namespace
|
||||
|
||||
CachedUserpics::CachedUserpics() {
|
||||
connect(&_clearTimer, SIGNAL(timeout()), this, SLOT(onClear()));
|
||||
QDir().mkpath(cWorkingDir() + qsl("tdata/temp"));
|
||||
}
|
||||
|
||||
QString CachedUserpics::get(const StorageKey &key, PeerData *peer) {
|
||||
uint64 ms = getms(true);
|
||||
auto i = _images.find(key);
|
||||
if (i != _images.cend()) {
|
||||
if (i->until) {
|
||||
i->until = ms + kNotifyDeletePhotoAfterMs;
|
||||
clearInMs(-kNotifyDeletePhotoAfterMs);
|
||||
}
|
||||
} else {
|
||||
Image v;
|
||||
if (key.first) {
|
||||
v.until = ms + kNotifyDeletePhotoAfterMs;
|
||||
clearInMs(-kNotifyDeletePhotoAfterMs);
|
||||
} else {
|
||||
v.until = 0;
|
||||
}
|
||||
v.path = cWorkingDir() + qsl("tdata/temp/") + QString::number(rand_value<uint64>(), 16) + qsl(".png");
|
||||
if (key.first || key.second) {
|
||||
peer->saveUserpic(v.path, st::notifyMacPhotoSize);
|
||||
} else {
|
||||
App::wnd()->iconLarge().save(v.path, "PNG");
|
||||
}
|
||||
i = _images.insert(key, v);
|
||||
_someSavedFlag = true;
|
||||
}
|
||||
return i->path;
|
||||
}
|
||||
|
||||
uint64 CachedUserpics::clear(uint64 ms) {
|
||||
uint64 result = 0;
|
||||
for (auto i = _images.begin(); i != _images.end();) {
|
||||
if (!i->until) {
|
||||
++i;
|
||||
continue;
|
||||
}
|
||||
if (i->until <= ms) {
|
||||
QFile(i->path).remove();
|
||||
i = _images.erase(i);
|
||||
} else {
|
||||
if (!result) {
|
||||
result = i->until;
|
||||
} else {
|
||||
accumulate_min(result, i->until);
|
||||
}
|
||||
++i;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void CachedUserpics::clearInMs(int ms) {
|
||||
if (ms < 0) {
|
||||
ms = -ms;
|
||||
if (_clearTimer.isActive() && _clearTimer.remainingTime() <= ms) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
_clearTimer.start(ms);
|
||||
}
|
||||
|
||||
void CachedUserpics::onClear() {
|
||||
auto ms = getms(true);
|
||||
auto minuntil = clear(ms);
|
||||
if (minuntil) {
|
||||
clearInMs(int(minuntil - ms));
|
||||
}
|
||||
}
|
||||
|
||||
CachedUserpics::~CachedUserpics() {
|
||||
if (_someSavedFlag) {
|
||||
psDeleteDir(cWorkingDir() + qsl("tdata/temp"));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Notifications
|
||||
} // namespace Window
|
57
Telegram/SourceFiles/window/notifications_utilities.h
Normal file
57
Telegram/SourceFiles/window/notifications_utilities.h
Normal file
@ -0,0 +1,57 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop version of Telegram messaging app, see https://telegram.org
|
||||
|
||||
Telegram Desktop is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
It is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
In addition, as a special exception, the copyright holders give permission
|
||||
to link the code of portions of this program with the OpenSSL library.
|
||||
|
||||
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "window/notifications_manager.h"
|
||||
|
||||
namespace Window {
|
||||
namespace Notifications {
|
||||
|
||||
class CachedUserpics : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
CachedUserpics();
|
||||
|
||||
QString get(const StorageKey &key, PeerData *peer);
|
||||
|
||||
~CachedUserpics();
|
||||
|
||||
private slots:
|
||||
void onClear();
|
||||
|
||||
private:
|
||||
void clearInMs(int ms);
|
||||
uint64 clear(uint64 ms);
|
||||
|
||||
struct Image {
|
||||
uint64 until;
|
||||
QString path;
|
||||
};
|
||||
using Images = QMap<StorageKey, Image>;
|
||||
Images _images;
|
||||
bool _someSavedFlag = false;
|
||||
SingleTimer _clearTimer;
|
||||
|
||||
};
|
||||
|
||||
} // namesapce Notifications
|
||||
} // namespace Window
|
@ -318,6 +318,8 @@
|
||||
'<(src_loc)/pspecific_linux.h',
|
||||
'<(src_loc)/platform/linux/linux_gdk_helper.cpp',
|
||||
'<(src_loc)/platform/linux/linux_gdk_helper.h',
|
||||
'<(src_loc)/platform/linux/linux_libnotify.cpp',
|
||||
'<(src_loc)/platform/linux/linux_libnotify.h',
|
||||
'<(src_loc)/platform/linux/linux_libs.cpp',
|
||||
'<(src_loc)/platform/linux/linux_libs.h',
|
||||
'<(src_loc)/platform/linux/file_dialog_linux.cpp',
|
||||
@ -486,6 +488,8 @@
|
||||
'<(src_loc)/window/notifications_manager.h',
|
||||
'<(src_loc)/window/notifications_manager_default.cpp',
|
||||
'<(src_loc)/window/notifications_manager_default.h',
|
||||
'<(src_loc)/window/notifications_utilities.cpp',
|
||||
'<(src_loc)/window/notifications_utilities.h',
|
||||
'<(src_loc)/window/section_widget.cpp',
|
||||
'<(src_loc)/window/section_widget.h',
|
||||
'<(src_loc)/window/slide_animation.cpp',
|
||||
|
Loading…
Reference in New Issue
Block a user