diff --git a/src/qt/notificator.cpp b/src/qt/notificator.cpp index 02ec506cc..611f28862 100644 --- a/src/qt/notificator.cpp +++ b/src/qt/notificator.cpp @@ -1,267 +1,262 @@ // Copyright (c) 2011-2016 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include #include #include #include #include #include #include #include #include #include #ifdef USE_DBUS #include #include #endif // Include ApplicationServices.h after QtDbus to avoid redefinition of check(). // This affects at least OSX 10.6. See /usr/include/AssertMacros.h for details. // Note: This could also be worked around using: // #define __ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES 0 #ifdef Q_OS_MAC #include #include #endif #ifdef USE_DBUS // https://wiki.ubuntu.com/NotificationDevelopmentGuidelines recommends at least // 128 const int FREEDESKTOP_NOTIFICATION_ICON_SIZE = 128; #endif Notificator::Notificator(const QString &_programName, QSystemTrayIcon *_trayIcon, QWidget *_parent) : QObject(_parent), parent(_parent), programName(_programName), mode(None), trayIcon(_trayIcon) #ifdef USE_DBUS , - interface(0) + interface(nullptr) #endif { if (_trayIcon && _trayIcon->supportsMessages()) { mode = QSystemTray; } #ifdef USE_DBUS interface = new QDBusInterface("org.freedesktop.Notifications", "/org/freedesktop/Notifications", "org.freedesktop.Notifications"); if (interface->isValid()) { mode = Freedesktop; } #endif #ifdef Q_OS_MAC // check if users OS has support for NSUserNotification if (MacNotificationHandler::instance() ->hasUserNotificationCenterSupport()) { mode = UserNotificationCenter; } #endif } Notificator::~Notificator() { #ifdef USE_DBUS delete interface; #endif } #ifdef USE_DBUS // Loosely based on http://www.qtcentre.org/archive/index.php/t-25879.html class FreedesktopImage { public: FreedesktopImage() {} explicit FreedesktopImage(const QImage &img); static int metaType(); // Image to variant that can be marshalled over DBus static QVariant toVariant(const QImage &img); private: int width, height, stride; bool hasAlpha; int channels; int bitsPerSample; QByteArray image; friend QDBusArgument &operator<<(QDBusArgument &a, const FreedesktopImage &i); friend const QDBusArgument &operator>>(const QDBusArgument &a, FreedesktopImage &i); }; Q_DECLARE_METATYPE(FreedesktopImage); // Image configuration settings const int CHANNELS = 4; const int BYTES_PER_PIXEL = 4; const int BITS_PER_SAMPLE = 8; FreedesktopImage::FreedesktopImage(const QImage &img) : width(img.width()), height(img.height()), stride(img.width() * BYTES_PER_PIXEL), hasAlpha(true), channels(CHANNELS), bitsPerSample(BITS_PER_SAMPLE) { // Convert 00xAARRGGBB to RGBA bytewise (endian-independent) format QImage tmp = img.convertToFormat(QImage::Format_ARGB32); const uint32_t *data = reinterpret_cast(tmp.bits()); unsigned int num_pixels = width * height; image.resize(num_pixels * BYTES_PER_PIXEL); for (unsigned int ptr = 0; ptr < num_pixels; ++ptr) { image[ptr * BYTES_PER_PIXEL + 0] = data[ptr] >> 16; // R image[ptr * BYTES_PER_PIXEL + 1] = data[ptr] >> 8; // G image[ptr * BYTES_PER_PIXEL + 2] = data[ptr]; // B image[ptr * BYTES_PER_PIXEL + 3] = data[ptr] >> 24; // A } } QDBusArgument &operator<<(QDBusArgument &a, const FreedesktopImage &i) { a.beginStructure(); a << i.width << i.height << i.stride << i.hasAlpha << i.bitsPerSample << i.channels << i.image; a.endStructure(); return a; } const QDBusArgument &operator>>(const QDBusArgument &a, FreedesktopImage &i) { a.beginStructure(); a >> i.width >> i.height >> i.stride >> i.hasAlpha >> i.bitsPerSample >> i.channels >> i.image; a.endStructure(); return a; } int FreedesktopImage::metaType() { return qDBusRegisterMetaType(); } QVariant FreedesktopImage::toVariant(const QImage &img) { FreedesktopImage fimg(img); return QVariant(FreedesktopImage::metaType(), &fimg); } void Notificator::notifyDBus(Class cls, const QString &title, const QString &text, const QIcon &icon, int millisTimeout) { - Q_UNUSED(cls); + // https://developer.gnome.org/notification-spec/ // Arguments for DBus call: QList args; // Program Name: args.append(programName); - // Unique ID of this notification type: + // Replaces ID; A value of 0 means that this notification won't replace any + // existing notifications: args.append(0U); // Application Icon, empty string args.append(QString()); // Summary args.append(title); // Body args.append(text); // Actions (none, actions are deprecated) QStringList actions; args.append(actions); // Hints QVariantMap hints; // If no icon specified, set icon based on class QIcon tmpicon; if (icon.isNull()) { QStyle::StandardPixmap sicon = QStyle::SP_MessageBoxQuestion; switch (cls) { case Information: sicon = QStyle::SP_MessageBoxInformation; break; case Warning: sicon = QStyle::SP_MessageBoxWarning; break; case Critical: sicon = QStyle::SP_MessageBoxCritical; break; default: break; } tmpicon = QApplication::style()->standardIcon(sicon); } else { tmpicon = icon; } hints["icon_data"] = FreedesktopImage::toVariant( tmpicon.pixmap(FREEDESKTOP_NOTIFICATION_ICON_SIZE).toImage()); args.append(hints); // Timeout (in msec) args.append(millisTimeout); // "Fire and forget" interface->callWithArgumentList(QDBus::NoBlock, "Notify", args); } #endif void Notificator::notifySystray(Class cls, const QString &title, - const QString &text, const QIcon &icon, - int millisTimeout) { - Q_UNUSED(icon); + const QString &text, int millisTimeout) { QSystemTrayIcon::MessageIcon sicon = QSystemTrayIcon::NoIcon; - switch (cls) // Set icon based on class - { + // Set icon based on class + switch (cls) { case Information: sicon = QSystemTrayIcon::Information; break; case Warning: sicon = QSystemTrayIcon::Warning; break; case Critical: sicon = QSystemTrayIcon::Critical; break; } trayIcon->showMessage(title, text, sicon, millisTimeout); } -// Based on Qt's tray icon implementation #ifdef Q_OS_MAC -void Notificator::notifyMacUserNotificationCenter(Class cls, - const QString &title, - const QString &text, - const QIcon &icon) { +void Notificator::notifyMacUserNotificationCenter(const QString &title, + const QString &text) { // icon is not supported by the user notification center yet. OSX will use // the app icon. MacNotificationHandler::instance()->showNotification(title, text); } - #endif void Notificator::notify(Class cls, const QString &title, const QString &text, const QIcon &icon, int millisTimeout) { switch (mode) { #ifdef USE_DBUS case Freedesktop: notifyDBus(cls, title, text, icon, millisTimeout); break; #endif case QSystemTray: - notifySystray(cls, title, text, icon, millisTimeout); + notifySystray(cls, title, text, millisTimeout); break; #ifdef Q_OS_MAC case UserNotificationCenter: - notifyMacUserNotificationCenter(cls, title, text, icon); + notifyMacUserNotificationCenter(title, text); break; #endif default: if (cls == Critical) { // Fall back to old fashioned pop-up dialog if critical and no // other notification available QMessageBox::critical(parent, title, text, QMessageBox::Ok, QMessageBox::Ok); } break; } } diff --git a/src/qt/notificator.h b/src/qt/notificator.h index d9ddba29a..6dc2a9e97 100644 --- a/src/qt/notificator.h +++ b/src/qt/notificator.h @@ -1,84 +1,83 @@ // Copyright (c) 2011-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_QT_NOTIFICATOR_H #define BITCOIN_QT_NOTIFICATOR_H #if defined(HAVE_CONFIG_H) #include #endif #include #include QT_BEGIN_NAMESPACE class QSystemTrayIcon; #ifdef USE_DBUS class QDBusInterface; #endif QT_END_NAMESPACE /** Cross-platform desktop notification client. */ class Notificator : public QObject { Q_OBJECT public: /** Create a new notificator. @note Ownership of trayIcon is not transferred to this object. */ Notificator(const QString &programName, QSystemTrayIcon *trayIcon, QWidget *parent); ~Notificator(); // Message class enum Class { Information, /**< Informational message */ Warning, /**< Notify user of potential problem */ Critical /**< An error occurred */ }; public Q_SLOTS: /** Show notification message. @param[in] cls general message class @param[in] title title shown with message @param[in] text message content @param[in] icon optional icon to show with message @param[in] millisTimeout notification timeout in milliseconds (defaults to 10 seconds) @note Platform implementations are free to ignore any of the provided fields except for \a text. */ void notify(Class cls, const QString &title, const QString &text, const QIcon &icon = QIcon(), int millisTimeout = 10000); private: QWidget *parent; enum Mode { None, /**< Ignore informational notifications, and show a modal pop-up dialog for Critical notifications. */ Freedesktop, /**< Use DBus org.freedesktop.Notifications */ - QSystemTray, /**< Use QSystemTray::showMessage */ + QSystemTray, /**< Use QSystemTrayIcon::showMessage() */ UserNotificationCenter /**< Use the 10.8+ User Notification Center (Mac only) */ }; QString programName; Mode mode; QSystemTrayIcon *trayIcon; #ifdef USE_DBUS QDBusInterface *interface; void notifyDBus(Class cls, const QString &title, const QString &text, const QIcon &icon, int millisTimeout); #endif void notifySystray(Class cls, const QString &title, const QString &text, - const QIcon &icon, int millisTimeout); + int millisTimeout); #ifdef Q_OS_MAC - void notifyMacUserNotificationCenter(Class cls, const QString &title, - const QString &text, - const QIcon &icon); + void notifyMacUserNotificationCenter(const QString &title, + const QString &text); #endif }; #endif // BITCOIN_QT_NOTIFICATOR_H