1 // Copyright (c) 2011-2017 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 <qt/notificator.h>
7 #include <QApplication>
9 #include <QImageWriter>
10 #include <QMessageBox>
13 #include <QSystemTrayIcon>
14 #include <QTemporaryFile>
20 // Include ApplicationServices.h after QtDbus to avoid redefinition of check().
21 // This affects at least OSX 10.6. See /usr/include/AssertMacros.h for details.
22 // Note: This could also be worked around using:
23 // #define __ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES 0
25 #include <ApplicationServices/ApplicationServices.h>
26 #include <qt/macnotificationhandler.h>
31 // https://wiki.ubuntu.com/NotificationDevelopmentGuidelines recommends at least 128
32 const int FREEDESKTOP_NOTIFICATION_ICON_SIZE
= 128;
35 Notificator::Notificator(const QString
&_programName
, QSystemTrayIcon
*_trayIcon
, QWidget
*_parent
) :
38 programName(_programName
),
45 if(_trayIcon
&& _trayIcon
->supportsMessages())
50 interface
= new QDBusInterface("org.freedesktop.Notifications",
51 "/org/freedesktop/Notifications", "org.freedesktop.Notifications");
52 if(interface
->isValid())
58 // check if users OS has support for NSUserNotification
59 if( MacNotificationHandler::instance()->hasUserNotificationCenterSupport()) {
60 mode
= UserNotificationCenter
;
65 Notificator::~Notificator()
74 // Loosely based on http://www.qtcentre.org/archive/index.php/t-25879.html
75 class FreedesktopImage
79 explicit FreedesktopImage(const QImage
&img
);
81 static int metaType();
83 // Image to variant that can be marshalled over DBus
84 static QVariant
toVariant(const QImage
&img
);
87 int width
, height
, stride
;
93 friend QDBusArgument
&operator<<(QDBusArgument
&a
, const FreedesktopImage
&i
);
94 friend const QDBusArgument
&operator>>(const QDBusArgument
&a
, FreedesktopImage
&i
);
97 Q_DECLARE_METATYPE(FreedesktopImage
);
99 // Image configuration settings
100 const int CHANNELS
= 4;
101 const int BYTES_PER_PIXEL
= 4;
102 const int BITS_PER_SAMPLE
= 8;
104 FreedesktopImage::FreedesktopImage(const QImage
&img
):
106 height(img
.height()),
107 stride(img
.width() * BYTES_PER_PIXEL
),
110 bitsPerSample(BITS_PER_SAMPLE
)
112 // Convert 00xAARRGGBB to RGBA bytewise (endian-independent) format
113 QImage tmp
= img
.convertToFormat(QImage::Format_ARGB32
);
114 const uint32_t *data
= reinterpret_cast<const uint32_t*>(tmp
.bits());
116 unsigned int num_pixels
= width
* height
;
117 image
.resize(num_pixels
* BYTES_PER_PIXEL
);
119 for(unsigned int ptr
= 0; ptr
< num_pixels
; ++ptr
)
121 image
[ptr
*BYTES_PER_PIXEL
+0] = data
[ptr
] >> 16; // R
122 image
[ptr
*BYTES_PER_PIXEL
+1] = data
[ptr
] >> 8; // G
123 image
[ptr
*BYTES_PER_PIXEL
+2] = data
[ptr
]; // B
124 image
[ptr
*BYTES_PER_PIXEL
+3] = data
[ptr
] >> 24; // A
128 QDBusArgument
&operator<<(QDBusArgument
&a
, const FreedesktopImage
&i
)
131 a
<< i
.width
<< i
.height
<< i
.stride
<< i
.hasAlpha
<< i
.bitsPerSample
<< i
.channels
<< i
.image
;
136 const QDBusArgument
&operator>>(const QDBusArgument
&a
, FreedesktopImage
&i
)
139 a
>> i
.width
>> i
.height
>> i
.stride
>> i
.hasAlpha
>> i
.bitsPerSample
>> i
.channels
>> i
.image
;
144 int FreedesktopImage::metaType()
146 return qDBusRegisterMetaType
<FreedesktopImage
>();
149 QVariant
FreedesktopImage::toVariant(const QImage
&img
)
151 FreedesktopImage
fimg(img
);
152 return QVariant(FreedesktopImage::metaType(), &fimg
);
155 void Notificator::notifyDBus(Class cls
, const QString
&title
, const QString
&text
, const QIcon
&icon
, int millisTimeout
)
158 // Arguments for DBus call:
159 QList
<QVariant
> args
;
162 args
.append(programName
);
164 // Unique ID of this notification type:
167 // Application Icon, empty string
168 args
.append(QString());
176 // Actions (none, actions are deprecated)
178 args
.append(actions
);
183 // If no icon specified, set icon based on class
187 QStyle::StandardPixmap sicon
= QStyle::SP_MessageBoxQuestion
;
190 case Information
: sicon
= QStyle::SP_MessageBoxInformation
; break;
191 case Warning
: sicon
= QStyle::SP_MessageBoxWarning
; break;
192 case Critical
: sicon
= QStyle::SP_MessageBoxCritical
; break;
195 tmpicon
= QApplication::style()->standardIcon(sicon
);
201 hints
["icon_data"] = FreedesktopImage::toVariant(tmpicon
.pixmap(FREEDESKTOP_NOTIFICATION_ICON_SIZE
).toImage());
205 args
.append(millisTimeout
);
208 interface
->callWithArgumentList(QDBus::NoBlock
, "Notify", args
);
212 void Notificator::notifySystray(Class cls
, const QString
&title
, const QString
&text
, const QIcon
&icon
, int millisTimeout
)
215 QSystemTrayIcon::MessageIcon sicon
= QSystemTrayIcon::NoIcon
;
216 switch(cls
) // Set icon based on class
218 case Information
: sicon
= QSystemTrayIcon::Information
; break;
219 case Warning
: sicon
= QSystemTrayIcon::Warning
; break;
220 case Critical
: sicon
= QSystemTrayIcon::Critical
; break;
222 trayIcon
->showMessage(title
, text
, sicon
, millisTimeout
);
225 // Based on Qt's tray icon implementation
227 void Notificator::notifyMacUserNotificationCenter(Class cls
, const QString
&title
, const QString
&text
, const QIcon
&icon
) {
228 // icon is not supported by the user notification center yet. OSX will use the app icon.
229 MacNotificationHandler::instance()->showNotification(title
, text
);
234 void Notificator::notify(Class cls
, const QString
&title
, const QString
&text
, const QIcon
&icon
, int millisTimeout
)
240 notifyDBus(cls
, title
, text
, icon
, millisTimeout
);
244 notifySystray(cls
, title
, text
, icon
, millisTimeout
);
247 case UserNotificationCenter
:
248 notifyMacUserNotificationCenter(cls
, title
, text
, icon
);
254 // Fall back to old fashioned pop-up dialog if critical and no other notification available
255 QMessageBox::critical(parent
, title
, text
, QMessageBox::Ok
, QMessageBox::Ok
);