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;    }}