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.
5 #include "notificator.h"
7 #include <QApplication>
10 #include <QImageWriter>
11 #include <QMessageBox>
14 #include <QSystemTrayIcon>
15 #include <QTemporaryFile>
21 // Include ApplicationServices.h after QtDbus to avoid redefinition of check().
22 // This affects at least OSX 10.6. See /usr/include/AssertMacros.h for details.
23 // Note: This could also be worked around using:
24 // #define __ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES 0
26 #include <ApplicationServices/ApplicationServices.h>
27 #include "macnotificationhandler.h"
32 // https://wiki.ubuntu.com/NotificationDevelopmentGuidelines recommends at least 128
33 const int FREEDESKTOP_NOTIFICATION_ICON_SIZE
= 128;
36 Notificator::Notificator(const QString
&_programName
, QSystemTrayIcon
*_trayIcon
, QWidget
*_parent
) :
39 programName(_programName
),
46 if(_trayIcon
&& _trayIcon
->supportsMessages())
51 interface
= new QDBusInterface("org.freedesktop.Notifications",
52 "/org/freedesktop/Notifications", "org.freedesktop.Notifications");
53 if(interface
->isValid())
59 // check if users OS has support for NSUserNotification
60 if( MacNotificationHandler::instance()->hasUserNotificationCenterSupport()) {
61 mode
= UserNotificationCenter
;
66 Notificator::~Notificator()
75 // Loosely based on http://www.qtcentre.org/archive/index.php/t-25879.html
76 class FreedesktopImage
80 explicit FreedesktopImage(const QImage
&img
);
82 static int metaType();
84 // Image to variant that can be marshalled over DBus
85 static QVariant
toVariant(const QImage
&img
);
88 int width
, height
, stride
;
94 friend QDBusArgument
&operator<<(QDBusArgument
&a
, const FreedesktopImage
&i
);
95 friend const QDBusArgument
&operator>>(const QDBusArgument
&a
, FreedesktopImage
&i
);
98 Q_DECLARE_METATYPE(FreedesktopImage
);
100 // Image configuration settings
101 const int CHANNELS
= 4;
102 const int BYTES_PER_PIXEL
= 4;
103 const int BITS_PER_SAMPLE
= 8;
105 FreedesktopImage::FreedesktopImage(const QImage
&img
):
107 height(img
.height()),
108 stride(img
.width() * BYTES_PER_PIXEL
),
111 bitsPerSample(BITS_PER_SAMPLE
)
113 // Convert 00xAARRGGBB to RGBA bytewise (endian-independent) format
114 QImage tmp
= img
.convertToFormat(QImage::Format_ARGB32
);
115 const uint32_t *data
= reinterpret_cast<const uint32_t*>(tmp
.bits());
117 unsigned int num_pixels
= width
* height
;
118 image
.resize(num_pixels
* BYTES_PER_PIXEL
);
120 for(unsigned int ptr
= 0; ptr
< num_pixels
; ++ptr
)
122 image
[ptr
*BYTES_PER_PIXEL
+0] = data
[ptr
] >> 16; // R
123 image
[ptr
*BYTES_PER_PIXEL
+1] = data
[ptr
] >> 8; // G
124 image
[ptr
*BYTES_PER_PIXEL
+2] = data
[ptr
]; // B
125 image
[ptr
*BYTES_PER_PIXEL
+3] = data
[ptr
] >> 24; // A
129 QDBusArgument
&operator<<(QDBusArgument
&a
, const FreedesktopImage
&i
)
132 a
<< i
.width
<< i
.height
<< i
.stride
<< i
.hasAlpha
<< i
.bitsPerSample
<< i
.channels
<< i
.image
;
137 const QDBusArgument
&operator>>(const QDBusArgument
&a
, FreedesktopImage
&i
)
140 a
>> i
.width
>> i
.height
>> i
.stride
>> i
.hasAlpha
>> i
.bitsPerSample
>> i
.channels
>> i
.image
;
145 int FreedesktopImage::metaType()
147 return qDBusRegisterMetaType
<FreedesktopImage
>();
150 QVariant
FreedesktopImage::toVariant(const QImage
&img
)
152 FreedesktopImage
fimg(img
);
153 return QVariant(FreedesktopImage::metaType(), &fimg
);
156 void Notificator::notifyDBus(Class cls
, const QString
&title
, const QString
&text
, const QIcon
&icon
, int millisTimeout
)
159 // Arguments for DBus call:
160 QList
<QVariant
> args
;
163 args
.append(programName
);
165 // Unique ID of this notification type:
168 // Application Icon, empty string
169 args
.append(QString());
177 // Actions (none, actions are deprecated)
179 args
.append(actions
);
184 // If no icon specified, set icon based on class
188 QStyle::StandardPixmap sicon
= QStyle::SP_MessageBoxQuestion
;
191 case Information
: sicon
= QStyle::SP_MessageBoxInformation
; break;
192 case Warning
: sicon
= QStyle::SP_MessageBoxWarning
; break;
193 case Critical
: sicon
= QStyle::SP_MessageBoxCritical
; break;
196 tmpicon
= QApplication::style()->standardIcon(sicon
);
202 hints
["icon_data"] = FreedesktopImage::toVariant(tmpicon
.pixmap(FREEDESKTOP_NOTIFICATION_ICON_SIZE
).toImage());
206 args
.append(millisTimeout
);
209 interface
->callWithArgumentList(QDBus::NoBlock
, "Notify", args
);
213 void Notificator::notifySystray(Class cls
, const QString
&title
, const QString
&text
, const QIcon
&icon
, int millisTimeout
)
216 QSystemTrayIcon::MessageIcon sicon
= QSystemTrayIcon::NoIcon
;
217 switch(cls
) // Set icon based on class
219 case Information
: sicon
= QSystemTrayIcon::Information
; break;
220 case Warning
: sicon
= QSystemTrayIcon::Warning
; break;
221 case Critical
: sicon
= QSystemTrayIcon::Critical
; break;
223 trayIcon
->showMessage(title
, text
, sicon
, millisTimeout
);
226 // Based on Qt's tray icon implementation
228 void Notificator::notifyMacUserNotificationCenter(Class cls
, const QString
&title
, const QString
&text
, const QIcon
&icon
) {
229 // icon is not supported by the user notification center yet. OSX will use the app icon.
230 MacNotificationHandler::instance()->showNotification(title
, text
);
235 void Notificator::notify(Class cls
, const QString
&title
, const QString
&text
, const QIcon
&icon
, int millisTimeout
)
241 notifyDBus(cls
, title
, text
, icon
, millisTimeout
);
245 notifySystray(cls
, title
, text
, icon
, millisTimeout
);
248 case UserNotificationCenter
:
249 notifyMacUserNotificationCenter(cls
, title
, text
, icon
);
255 // Fall back to old fashioned pop-up dialog if critical and no other notification available
256 QMessageBox::critical(parent
, title
, text
, QMessageBox::Ok
, QMessageBox::Ok
);