Bitcoin ABC 0.30.5
P2P Digital Currency
notificator.cpp
Go to the documentation of this file.
1// Copyright (c) 2011-2016 The Bitcoin Core developers
2// Distributed under the MIT software license, see the accompanying
3// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
5#include <qt/notificator.h>
6
7#include <QApplication>
8#include <QByteArray>
9#include <QImageWriter>
10#include <QMessageBox>
11#include <QMetaType>
12#include <QStyle>
13#include <QSystemTrayIcon>
14#include <QTemporaryFile>
15#include <QVariant>
16#ifdef USE_DBUS
17#include <QtDBus>
18#include <cstdint>
19#endif
20#ifdef Q_OS_MAC
22#endif
23
24#ifdef USE_DBUS
25// https://wiki.ubuntu.com/NotificationDevelopmentGuidelines recommends at least
26// 128
27const int FREEDESKTOP_NOTIFICATION_ICON_SIZE = 128;
28#endif
29
30Notificator::Notificator(const QString &_programName,
31 QSystemTrayIcon *_trayIcon, QWidget *_parent)
32 : QObject(_parent), parent(_parent), programName(_programName), mode(None),
33 trayIcon(_trayIcon)
34#ifdef USE_DBUS
35 ,
36 interface(nullptr)
37#endif
38{
39 if (_trayIcon && _trayIcon->supportsMessages()) {
41 }
42#ifdef USE_DBUS
43 interface = new QDBusInterface("org.freedesktop.Notifications",
44 "/org/freedesktop/Notifications",
45 "org.freedesktop.Notifications");
46 if (interface->isValid()) {
48 }
49#endif
50#ifdef Q_OS_MAC
51 // check if users OS has support for NSUserNotification
53 ->hasUserNotificationCenterSupport()) {
55 }
56#endif
57}
58
60#ifdef USE_DBUS
61 delete interface;
62#endif
63}
64
65#ifdef USE_DBUS
66
67// Loosely based on http://www.qtcentre.org/archive/index.php/t-25879.html
68class FreedesktopImage {
69public:
70 FreedesktopImage() {}
71 explicit FreedesktopImage(const QImage &img);
72
73 static int metaType();
74
75 // Image to variant that can be marshalled over DBus
76 static QVariant toVariant(const QImage &img);
77
78private:
79 int width, height, stride;
80 bool hasAlpha;
81 int channels;
82 int bitsPerSample;
83 QByteArray image;
84
85 friend QDBusArgument &operator<<(QDBusArgument &a,
86 const FreedesktopImage &i);
87 friend const QDBusArgument &operator>>(const QDBusArgument &a,
88 FreedesktopImage &i);
89};
90
91Q_DECLARE_METATYPE(FreedesktopImage);
92
93// Image configuration settings
94const int CHANNELS = 4;
95const int BYTES_PER_PIXEL = 4;
96const int BITS_PER_SAMPLE = 8;
97
98FreedesktopImage::FreedesktopImage(const QImage &img)
99 : width(img.width()), height(img.height()),
100 stride(img.width() * BYTES_PER_PIXEL), hasAlpha(true), channels(CHANNELS),
101 bitsPerSample(BITS_PER_SAMPLE) {
102 // Convert 00xAARRGGBB to RGBA bytewise (endian-independent) format
103 QImage tmp = img.convertToFormat(QImage::Format_ARGB32);
104 const uint32_t *data = reinterpret_cast<const uint32_t *>(tmp.bits());
105
106 unsigned int num_pixels = width * height;
107 image.resize(num_pixels * BYTES_PER_PIXEL);
108
109 for (unsigned int ptr = 0; ptr < num_pixels; ++ptr) {
110 image[ptr * BYTES_PER_PIXEL + 0] = data[ptr] >> 16; // R
111 image[ptr * BYTES_PER_PIXEL + 1] = data[ptr] >> 8; // G
112 image[ptr * BYTES_PER_PIXEL + 2] = data[ptr]; // B
113 image[ptr * BYTES_PER_PIXEL + 3] = data[ptr] >> 24; // A
114 }
115}
116
117QDBusArgument &operator<<(QDBusArgument &a, const FreedesktopImage &i) {
118 a.beginStructure();
119 a << i.width << i.height << i.stride << i.hasAlpha << i.bitsPerSample
120 << i.channels << i.image;
121 a.endStructure();
122 return a;
123}
124
125const QDBusArgument &operator>>(const QDBusArgument &a, FreedesktopImage &i) {
126 a.beginStructure();
127 a >> i.width >> i.height >> i.stride >> i.hasAlpha >> i.bitsPerSample >>
128 i.channels >> i.image;
129 a.endStructure();
130 return a;
131}
132
133int FreedesktopImage::metaType() {
134 return qDBusRegisterMetaType<FreedesktopImage>();
135}
136
137QVariant FreedesktopImage::toVariant(const QImage &img) {
138 FreedesktopImage fimg(img);
139 return QVariant(FreedesktopImage::metaType(), &fimg);
140}
141
142void Notificator::notifyDBus(Class cls, const QString &title,
143 const QString &text, const QIcon &icon,
144 int millisTimeout) {
145 // https://developer.gnome.org/notification-spec/
146 // Arguments for DBus call:
147 QList<QVariant> args;
148
149 // Program Name:
150 args.append(programName);
151
152 // Replaces ID; A value of 0 means that this notification won't replace any
153 // existing notifications:
154 args.append(0U);
155
156 // Application Icon, empty string
157 args.append(QString());
158
159 // Summary
160 args.append(title);
161
162 // Body
163 args.append(text);
164
165 // Actions (none, actions are deprecated)
166 QStringList actions;
167 args.append(actions);
168
169 // Hints
170 QVariantMap hints;
171
172 // If no icon specified, set icon based on class
173 QIcon tmpicon;
174 if (icon.isNull()) {
175 QStyle::StandardPixmap sicon = QStyle::SP_MessageBoxQuestion;
176 switch (cls) {
177 case Information:
178 sicon = QStyle::SP_MessageBoxInformation;
179 break;
180 case Warning:
181 sicon = QStyle::SP_MessageBoxWarning;
182 break;
183 case Critical:
184 sicon = QStyle::SP_MessageBoxCritical;
185 break;
186 default:
187 break;
188 }
189 tmpicon = QApplication::style()->standardIcon(sicon);
190 } else {
191 tmpicon = icon;
192 }
193 hints["icon_data"] = FreedesktopImage::toVariant(
194 tmpicon.pixmap(FREEDESKTOP_NOTIFICATION_ICON_SIZE).toImage());
195 args.append(hints);
196
197 // Timeout (in msec)
198 args.append(millisTimeout);
199
200 // "Fire and forget"
201 interface->callWithArgumentList(QDBus::NoBlock, "Notify", args);
202}
203#endif
204
205void Notificator::notifySystray(Class cls, const QString &title,
206 const QString &text, int millisTimeout) {
207 QSystemTrayIcon::MessageIcon sicon = QSystemTrayIcon::NoIcon;
208 // Set icon based on class
209 switch (cls) {
210 case Information:
211 sicon = QSystemTrayIcon::Information;
212 break;
213 case Warning:
214 sicon = QSystemTrayIcon::Warning;
215 break;
216 case Critical:
217 sicon = QSystemTrayIcon::Critical;
218 break;
219 }
220 trayIcon->showMessage(title, text, sicon, millisTimeout);
221}
222
223#ifdef Q_OS_MAC
224void Notificator::notifyMacUserNotificationCenter(const QString &title,
225 const QString &text) {
226 // icon is not supported by the user notification center yet. OSX will use
227 // the app icon.
229}
230#endif
231
232void Notificator::notify(Class cls, const QString &title, const QString &text,
233 const QIcon &icon, int millisTimeout) {
234 switch (mode) {
235#ifdef USE_DBUS
236 case Freedesktop:
237 notifyDBus(cls, title, text, icon, millisTimeout);
238 break;
239#endif
240 case QSystemTray:
241 notifySystray(cls, title, text, millisTimeout);
242 break;
243#ifdef Q_OS_MAC
245 notifyMacUserNotificationCenter(title, text);
246 break;
247#endif
248 default:
249 if (cls == Critical) {
250 // Fall back to old fashioned pop-up dialog if critical and no
251 // other notification available
252 QMessageBox::critical(parent, title, text, QMessageBox::Ok,
253 QMessageBox::Ok);
254 }
255 break;
256 }
257}
static MacNotificationHandler * instance()
void showNotification(const QString &title, const QString &text)
shows a macOS 10.8+ UserNotification in the UserNotificationCenter
QString programName
Definition: notificator.h:66
QWidget * parent
Definition: notificator.h:57
@ Information
Informational message.
Definition: notificator.h:37
@ Critical
An error occurred.
Definition: notificator.h:39
@ Warning
Notify user of potential problem.
Definition: notificator.h:38
@ UserNotificationCenter
Use the 10.8+ User Notification Center (Mac only)
Definition: notificator.h:63
@ QSystemTray
Use QSystemTrayIcon::showMessage()
Definition: notificator.h:62
@ Freedesktop
Use DBus org.freedesktop.Notifications.
Definition: notificator.h:61
void notifySystray(Class cls, const QString &title, const QString &text, int millisTimeout)
Notificator(const QString &programName, QSystemTrayIcon *trayIcon, QWidget *parent)
Create a new notificator.
Definition: notificator.cpp:30
QSystemTrayIcon * trayIcon
Definition: notificator.h:68
void notify(Class cls, const QString &title, const QString &text, const QIcon &icon=QIcon(), int millisTimeout=10000)
Show notification message.
std::ostream & operator<<(std::ostream &os, BigO const &bigO)