Inside Bitcoin
Opening the selected file…
Inside Bitcoin
Opening the selected file…
The code behind the network, with room to understand it.
Release published 2026-10-28 · Snapshot fetched 2026-11-01. Latest stable release at fetch time; development branches and Git history are excluded. Only the selected code window and visible folders load here.
1// Copyright (c) 2011-present The Bitcoin Core developers2// Distributed under the MIT software license, see the accompanying3// file COPYING or http://www.opensource.org/licenses/mit-license.php.5#include <bitcoin-build-config.h> // IWYU pragma: keep7#include <qt/notificator.h>9#include <QApplication>10#include <QByteArray>11#include <QImageWriter>12#include <QMessageBox>13#include <QMetaType>14#include <QStyle>15#include <QSystemTrayIcon>16#include <QTemporaryFile>17#include <QVariant>18#ifdef USE_DBUS19#include <QDBusMetaType>20#include <QtDBus>21#include <cstdint>22#endif23#ifdef Q_OS_MACOS24#include <qt/macnotificationhandler.h>25#endif28#ifdef USE_DBUS29// https://wiki.ubuntu.com/NotificationDevelopmentGuidelines recommends at least 12830const int FREEDESKTOP_NOTIFICATION_ICON_SIZE = 128;31#endif33Notificator::Notificator(const QString &_programName, QSystemTrayIcon *_trayIcon, QWidget *_parent) :34QObject(_parent),35parent(_parent),36programName(_programName),37trayIcon(_trayIcon)38{39if(_trayIcon && _trayIcon->supportsMessages())40{41mode = QSystemTray;42}43#ifdef USE_DBUS44interface = new QDBusInterface("org.freedesktop.Notifications",45"/org/freedesktop/Notifications", "org.freedesktop.Notifications");46if(interface->isValid())47{48mode = Freedesktop;49}50#endif51#ifdef Q_OS_MACOS52// check if users OS has support for NSUserNotification53if( MacNotificationHandler::instance()->hasUserNotificationCenterSupport()) {54mode = UserNotificationCenter;55}56#endif57}59Notificator::~Notificator()60{61#ifdef USE_DBUS62delete interface;63#endif64}66#ifdef USE_DBUS68// Loosely based on https://www.qtcentre.org/archive/index.php/t-25879.html69class FreedesktopImage70{71public:72FreedesktopImage() = default;73explicit FreedesktopImage(const QImage &img);75// Image to variant that can be marshalled over DBus76static QVariant toVariant(const QImage &img);78private:79int width, height, stride;80bool hasAlpha;81int channels;82int bitsPerSample;83QByteArray image;85friend QDBusArgument &operator<<(QDBusArgument &a, const FreedesktopImage &i);86friend const QDBusArgument &operator>>(const QDBusArgument &a, FreedesktopImage &i);87};89Q_DECLARE_METATYPE(FreedesktopImage);91// Image configuration settings92const int CHANNELS = 4;93const int BYTES_PER_PIXEL = 4;94const int BITS_PER_SAMPLE = 8;96FreedesktopImage::FreedesktopImage(const QImage &img):97width(img.width()),98height(img.height()),99stride(img.width() * BYTES_PER_PIXEL),100hasAlpha(true),101channels(CHANNELS),102bitsPerSample(BITS_PER_SAMPLE)103{104// Convert 00xAARRGGBB to RGBA bytewise (endian-independent) format105QImage tmp = img.convertToFormat(QImage::Format_ARGB32);106const uint32_t *data = reinterpret_cast<const uint32_t*>(tmp.bits());108unsigned int num_pixels = width * height;109image.resize(num_pixels * BYTES_PER_PIXEL);111for(unsigned int ptr = 0; ptr < num_pixels; ++ptr)112{113image[ptr * BYTES_PER_PIXEL + 0] = char(data[ptr] >> 16); // R114image[ptr * BYTES_PER_PIXEL + 1] = char(data[ptr] >> 8); // G115image[ptr * BYTES_PER_PIXEL + 2] = char(data[ptr]); // B116image[ptr * BYTES_PER_PIXEL + 3] = char(data[ptr] >> 24); // A117}118}120QDBusArgument &operator<<(QDBusArgument &a, const FreedesktopImage &i)121{122a.beginStructure();123a << i.width << i.height << i.stride << i.hasAlpha << i.bitsPerSample << i.channels << i.image;124a.endStructure();125return a;126}128const QDBusArgument &operator>>(const QDBusArgument &a, FreedesktopImage &i)129{130a.beginStructure();131a >> i.width >> i.height >> i.stride >> i.hasAlpha >> i.bitsPerSample >> i.channels >> i.image;132a.endStructure();133return a;134}136QVariant FreedesktopImage::toVariant(const QImage &img)137{138FreedesktopImage fimg(img);139return QVariant(qDBusRegisterMetaType<FreedesktopImage>(), &fimg);140}142void Notificator::notifyDBus(Class cls, const QString &title, const QString &text, const QIcon &icon, int millisTimeout)143{144// Arguments for DBus "Notify" call:145QList<QVariant> args;147// Program Name:148args.append(programName);150// Replaces ID; A value of 0 means that this notification won't replace any existing notifications:151args.append(0U);153// Application Icon, empty string154args.append(QString());156// Summary157args.append(title);159// Body160args.append(text);162// Actions (none, actions are deprecated)163QStringList actions;164args.append(actions);166// Hints167QVariantMap hints;169// If no icon specified, set icon based on class170QIcon tmpicon;171if(icon.isNull())172{173QStyle::StandardPixmap sicon = QStyle::SP_MessageBoxQuestion;174switch(cls)175{176case Information: sicon = QStyle::SP_MessageBoxInformation; break;177case Warning: sicon = QStyle::SP_MessageBoxWarning; break;178case Critical: sicon = QStyle::SP_MessageBoxCritical; break;179} // no default case, so the compiler can warn about missing cases180tmpicon = QApplication::style()->standardIcon(sicon);181}182else183{184tmpicon = icon;185}186hints["icon_data"] = FreedesktopImage::toVariant(tmpicon.pixmap(FREEDESKTOP_NOTIFICATION_ICON_SIZE).toImage());187args.append(hints);189// Timeout (in msec)190args.append(millisTimeout);192// "Fire and forget"193interface->callWithArgumentList(QDBus::NoBlock, "Notify", args);194}195#endif197void Notificator::notifySystray(Class cls, const QString &title, const QString &text, int millisTimeout)198{199QSystemTrayIcon::MessageIcon sicon = QSystemTrayIcon::NoIcon;200switch(cls) // Set icon based on class201{202case Information: sicon = QSystemTrayIcon::Information; break;203case Warning: sicon = QSystemTrayIcon::Warning; break;204case Critical: sicon = QSystemTrayIcon::Critical; break;205}206trayIcon->showMessage(title, text, sicon, millisTimeout);207}209#ifdef Q_OS_MACOS210void Notificator::notifyMacUserNotificationCenter(const QString &title, const QString &text)211{212// icon is not supported by the user notification center yet. OSX will use the app icon.213MacNotificationHandler::instance()->showNotification(title, text);214}215#endif217void Notificator::notify(Class cls, const QString &title, const QString &text, const QIcon &icon, int millisTimeout)218{219switch(mode)220{221#ifdef USE_DBUS222case Freedesktop:223notifyDBus(cls, title, text, icon, millisTimeout);224break;225#endif226case QSystemTray:227notifySystray(cls, title, text, millisTimeout);228break;229#ifdef Q_OS_MACOS230case UserNotificationCenter:231notifyMacUserNotificationCenter(title, text);232break;233#endif234default:235if(cls == Critical)236{237// Fall back to old fashioned pop-up dialog if critical and no other notification available238QMessageBox::critical(parent, title, text, QMessageBox::Ok, QMessageBox::Ok);239}240break;241}242}
Independent explanations by MyBitcoinExplorer. Not affiliated with or endorsed by Bitcoin Core. Guides are educational and do not replace the source or its tests.
Bitcoin Core source © its contributors, distributed under the MIT license. Original notices and bundled third-party licenses are retained in the source tree.