git / moonbite-core / src/qt/notificator.cpp · raw
// Copyright (c) 2011-2018 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 <qt/notificator.h>#include <QApplication>#include <QByteArray>#include <QImageWriter>#include <QMessageBox>#include <QMetaType>#include <QStyle>#include <QSystemTrayIcon>#include <QTemporaryFile>#include <QVariant>#ifdef USE_DBUS#include <stdint.h>#include <QtDBus>#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 <ApplicationServices/ApplicationServices.h>#include <qt/macnotificationhandler.h>#endif#ifdef USE_DBUS// https://wiki.ubuntu.com/NotificationDevelopmentGuidelines recommends at least 128const int FREEDESKTOP_NOTIFICATION_ICON_SIZE = 128;#endifNotificator::Notificator(const QString &_programName, QSystemTrayIcon *_trayIcon, QWidget *_parent) : QObject(_parent), parent(_parent), programName(_programName), mode(None), trayIcon(_trayIcon)#ifdef USE_DBUS ,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.htmlclass 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 settingsconst 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<const uint32_t*>(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<FreedesktopImage>();}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){ // https://developer.gnome.org/notification-spec/ // Arguments for DBus "Notify" call: QList<QVariant> args; // Program Name: args.append(programName); // 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);}#endifvoid Notificator::notifySystray(Class cls, const QString &title, const QString &text, int millisTimeout){ QSystemTrayIcon::MessageIcon sicon = QSystemTrayIcon::NoIcon; switch(cls) // Set icon based on class { case Information: sicon = QSystemTrayIcon::Information; break; case Warning: sicon = QSystemTrayIcon::Warning; break; case Critical: sicon = QSystemTrayIcon::Critical; break; } trayIcon->showMessage(title, text, sicon, millisTimeout);}#ifdef Q_OS_MACvoid 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);}#endifvoid 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, millisTimeout); break;#ifdef Q_OS_MAC case UserNotificationCenter: 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; }}