LCOV - code coverage report
Current view: top level - src/qt - notificator.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 0 107 0.0 %
Date: 2020-09-26 01:30:44 Functions: 0 22 0.0 %

          Line data    Source code
       1             : // Copyright (c) 2011-2018 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.
       4             : 
       5             : #include <qt/notificator.h>
       6             : 
       7             : #include <QApplication>
       8             : #include <QByteArray>
       9             : #include <QImageWriter>
      10             : #include <QMessageBox>
      11             : #include <QMetaType>
      12             : #include <QStyle>
      13             : #include <QSystemTrayIcon>
      14             : #include <QTemporaryFile>
      15             : #include <QVariant>
      16             : #ifdef USE_DBUS
      17             : #include <stdint.h>
      18             : #include <QtDBus>
      19             : #endif
      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
      24             : #ifdef Q_OS_MAC
      25             : #include <ApplicationServices/ApplicationServices.h>
      26             : #include <qt/macnotificationhandler.h>
      27             : #endif
      28             : 
      29             : 
      30             : #ifdef USE_DBUS
      31             : // https://wiki.ubuntu.com/NotificationDevelopmentGuidelines recommends at least 128
      32             : const int FREEDESKTOP_NOTIFICATION_ICON_SIZE = 128;
      33             : #endif
      34             : 
      35           0 : Notificator::Notificator(const QString &_programName, QSystemTrayIcon *_trayIcon, QWidget *_parent) :
      36           0 :     QObject(_parent),
      37           0 :     parent(_parent),
      38           0 :     programName(_programName),
      39           0 :     mode(None),
      40           0 :     trayIcon(_trayIcon)
      41             : #ifdef USE_DBUS
      42           0 :     ,interface(nullptr)
      43             : #endif
      44           0 : {
      45           0 :     if(_trayIcon && _trayIcon->supportsMessages())
      46             :     {
      47           0 :         mode = QSystemTray;
      48           0 :     }
      49             : #ifdef USE_DBUS
      50           0 :     interface = new QDBusInterface("org.freedesktop.Notifications",
      51           0 :         "/org/freedesktop/Notifications", "org.freedesktop.Notifications");
      52           0 :     if(interface->isValid())
      53             :     {
      54           0 :         mode = Freedesktop;
      55           0 :     }
      56             : #endif
      57             : #ifdef Q_OS_MAC
      58             :     // check if users OS has support for NSUserNotification
      59           0 :     if( MacNotificationHandler::instance()->hasUserNotificationCenterSupport()) {
      60           0 :         mode = UserNotificationCenter;
      61           0 :     }
      62             : #endif
      63           0 : }
      64             : 
      65           0 : Notificator::~Notificator()
      66           0 : {
      67             : #ifdef USE_DBUS
      68           0 :     delete interface;
      69             : #endif
      70           0 : }
      71             : 
      72             : #ifdef USE_DBUS
      73             : 
      74             : // Loosely based on http://www.qtcentre.org/archive/index.php/t-25879.html
      75           0 : class FreedesktopImage
      76             : {
      77             : public:
      78           0 :     FreedesktopImage() {}
      79             :     explicit FreedesktopImage(const QImage &img);
      80             : 
      81             :     static int metaType();
      82             : 
      83             :     // Image to variant that can be marshalled over DBus
      84             :     static QVariant toVariant(const QImage &img);
      85             : 
      86             : private:
      87             :     int width, height, stride;
      88             :     bool hasAlpha;
      89             :     int channels;
      90             :     int bitsPerSample;
      91             :     QByteArray image;
      92             : 
      93             :     friend QDBusArgument &operator<<(QDBusArgument &a, const FreedesktopImage &i);
      94             :     friend const QDBusArgument &operator>>(const QDBusArgument &a, FreedesktopImage &i);
      95             : };
      96             : 
      97           0 : Q_DECLARE_METATYPE(FreedesktopImage);
      98             : 
      99             : // Image configuration settings
     100             : const int CHANNELS = 4;
     101             : const int BYTES_PER_PIXEL = 4;
     102             : const int BITS_PER_SAMPLE = 8;
     103             : 
     104           0 : FreedesktopImage::FreedesktopImage(const QImage &img):
     105           0 :     width(img.width()),
     106           0 :     height(img.height()),
     107           0 :     stride(img.width() * BYTES_PER_PIXEL),
     108           0 :     hasAlpha(true),
     109           0 :     channels(CHANNELS),
     110           0 :     bitsPerSample(BITS_PER_SAMPLE)
     111           0 : {
     112             :     // Convert 00xAARRGGBB to RGBA bytewise (endian-independent) format
     113           0 :     QImage tmp = img.convertToFormat(QImage::Format_ARGB32);
     114           0 :     const uint32_t *data = reinterpret_cast<const uint32_t*>(tmp.bits());
     115             : 
     116           0 :     unsigned int num_pixels = width * height;
     117           0 :     image.resize(num_pixels * BYTES_PER_PIXEL);
     118             : 
     119           0 :     for(unsigned int ptr = 0; ptr < num_pixels; ++ptr)
     120             :     {
     121           0 :         image[ptr*BYTES_PER_PIXEL+0] = data[ptr] >> 16; // R
     122           0 :         image[ptr*BYTES_PER_PIXEL+1] = data[ptr] >> 8;  // G
     123           0 :         image[ptr*BYTES_PER_PIXEL+2] = data[ptr];       // B
     124           0 :         image[ptr*BYTES_PER_PIXEL+3] = data[ptr] >> 24; // A
     125             :     }
     126           0 : }
     127             : 
     128           0 : QDBusArgument &operator<<(QDBusArgument &a, const FreedesktopImage &i)
     129             : {
     130           0 :     a.beginStructure();
     131           0 :     a << i.width << i.height << i.stride << i.hasAlpha << i.bitsPerSample << i.channels << i.image;
     132           0 :     a.endStructure();
     133           0 :     return a;
     134             : }
     135             : 
     136           0 : const QDBusArgument &operator>>(const QDBusArgument &a, FreedesktopImage &i)
     137             : {
     138           0 :     a.beginStructure();
     139           0 :     a >> i.width >> i.height >> i.stride >> i.hasAlpha >> i.bitsPerSample >> i.channels >> i.image;
     140           0 :     a.endStructure();
     141           0 :     return a;
     142             : }
     143             : 
     144           0 : int FreedesktopImage::metaType()
     145             : {
     146           0 :     return qDBusRegisterMetaType<FreedesktopImage>();
     147             : }
     148             : 
     149           0 : QVariant FreedesktopImage::toVariant(const QImage &img)
     150             : {
     151           0 :     FreedesktopImage fimg(img);
     152           0 :     return QVariant(FreedesktopImage::metaType(), &fimg);
     153           0 : }
     154             : 
     155           0 : void Notificator::notifyDBus(Class cls, const QString &title, const QString &text, const QIcon &icon, int millisTimeout)
     156             : {
     157             :     // https://developer.gnome.org/notification-spec/
     158             :     // Arguments for DBus "Notify" call:
     159           0 :     QList<QVariant> args;
     160             : 
     161             :     // Program Name:
     162           0 :     args.append(programName);
     163             : 
     164             :     // Replaces ID; A value of 0 means that this notification won't replace any existing notifications:
     165           0 :     args.append(0U);
     166             : 
     167             :     // Application Icon, empty string
     168           0 :     args.append(QString());
     169             : 
     170             :     // Summary
     171           0 :     args.append(title);
     172             : 
     173             :     // Body
     174           0 :     args.append(text);
     175             : 
     176             :     // Actions (none, actions are deprecated)
     177           0 :     QStringList actions;
     178           0 :     args.append(actions);
     179             : 
     180             :     // Hints
     181           0 :     QVariantMap hints;
     182             : 
     183             :     // If no icon specified, set icon based on class
     184           0 :     QIcon tmpicon;
     185           0 :     if(icon.isNull())
     186             :     {
     187             :         QStyle::StandardPixmap sicon = QStyle::SP_MessageBoxQuestion;
     188           0 :         switch(cls)
     189             :         {
     190           0 :         case Information: sicon = QStyle::SP_MessageBoxInformation; break;
     191           0 :         case Warning: sicon = QStyle::SP_MessageBoxWarning; break;
     192           0 :         case Critical: sicon = QStyle::SP_MessageBoxCritical; break;
     193             :         default: break;
     194             :         }
     195           0 :         tmpicon = QApplication::style()->standardIcon(sicon);
     196           0 :     }
     197             :     else
     198             :     {
     199           0 :         tmpicon = icon;
     200             :     }
     201           0 :     hints["icon_data"] = FreedesktopImage::toVariant(tmpicon.pixmap(FREEDESKTOP_NOTIFICATION_ICON_SIZE).toImage());
     202           0 :     args.append(hints);
     203             : 
     204             :     // Timeout (in msec)
     205           0 :     args.append(millisTimeout);
     206             : 
     207             :     // "Fire and forget"
     208           0 :     interface->callWithArgumentList(QDBus::NoBlock, "Notify", args);
     209           0 : }
     210             : #endif
     211             : 
     212           0 : void Notificator::notifySystray(Class cls, const QString &title, const QString &text, int millisTimeout)
     213             : {
     214             :     QSystemTrayIcon::MessageIcon sicon = QSystemTrayIcon::NoIcon;
     215           0 :     switch(cls) // Set icon based on class
     216             :     {
     217           0 :     case Information: sicon = QSystemTrayIcon::Information; break;
     218           0 :     case Warning: sicon = QSystemTrayIcon::Warning; break;
     219           0 :     case Critical: sicon = QSystemTrayIcon::Critical; break;
     220             :     }
     221           0 :     trayIcon->showMessage(title, text, sicon, millisTimeout);
     222           0 : }
     223             : 
     224             : #ifdef Q_OS_MAC
     225           0 : void Notificator::notifyMacUserNotificationCenter(const QString &title, const QString &text)
     226             : {
     227             :     // icon is not supported by the user notification center yet. OSX will use the app icon.
     228           0 :     MacNotificationHandler::instance()->showNotification(title, text);
     229           0 : }
     230             : #endif
     231             : 
     232           0 : void Notificator::notify(Class cls, const QString &title, const QString &text, const QIcon &icon, int millisTimeout)
     233             : {
     234           0 :     switch(mode)
     235             :     {
     236             : #ifdef USE_DBUS
     237             :     case Freedesktop:
     238           0 :         notifyDBus(cls, title, text, icon, millisTimeout);
     239           0 :         break;
     240             : #endif
     241             :     case QSystemTray:
     242           0 :         notifySystray(cls, title, text, millisTimeout);
     243           0 :         break;
     244             : #ifdef Q_OS_MAC
     245             :     case UserNotificationCenter:
     246           0 :         notifyMacUserNotificationCenter(title, text);
     247           0 :         break;
     248             : #endif
     249             :     default:
     250           0 :         if(cls == Critical)
     251             :         {
     252             :             // Fall back to old fashioned pop-up dialog if critical and no other notification available
     253           0 :             QMessageBox::critical(parent, title, text, QMessageBox::Ok, QMessageBox::Ok);
     254           0 :         }
     255             :         break;
     256             :     }
     257           0 : }

Generated by: LCOV version 1.15