mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-11-11 06:28:31 +01:00
-BEGIN VERIFY SCRIPT-
regex_string='^(?!//).*(AC_APPLE_UNIVERSAL_BUILD|BOOST_PROCESS_USE_STD_FS|CHAR_EQUALS_INT8|CLIENT_VERSION_BUILD|CLIENT_VERSION_IS_RELEASE|CLIENT_VERSION_MAJOR|CLIENT_VERSION_MINOR|COPYRIGHT_HOLDERS|COPYRIGHT_HOLDERS_FINAL|COPYRIGHT_HOLDERS_SUBSTITUTION|COPYRIGHT_YEAR|ENABLE_ARM_SHANI|ENABLE_AVX2|ENABLE_EXTERNAL_SIGNER|ENABLE_SSE41|ENABLE_TRACING|ENABLE_WALLET|ENABLE_X86_SHANI|ENABLE_ZMQ|HAVE_BOOST|HAVE_BUILTIN_CLZL|HAVE_BUILTIN_CLZLL|HAVE_BYTESWAP_H|HAVE_CLMUL|HAVE_CONSENSUS_LIB|HAVE_CXX20|HAVE_DECL_BE16TOH|HAVE_DECL_BE32TOH|HAVE_DECL_BE64TOH|HAVE_DECL_BSWAP_16|HAVE_DECL_BSWAP_32|HAVE_DECL_BSWAP_64|HAVE_DECL_FORK|HAVE_DECL_FREEIFADDRS|HAVE_DECL_GETIFADDRS|HAVE_DECL_HTOBE16|HAVE_DECL_HTOBE32|HAVE_DECL_HTOBE64|HAVE_DECL_HTOLE16|HAVE_DECL_HTOLE32|HAVE_DECL_HTOLE64|HAVE_DECL_LE16TOH|HAVE_DECL_LE32TOH|HAVE_DECL_LE64TOH|HAVE_DECL_PIPE2|HAVE_DECL_SETSID|HAVE_DECL_STRERROR_R|HAVE_DEFAULT_VISIBILITY_ATTRIBUTE|HAVE_DLFCN_H|HAVE_DLLEXPORT_ATTRIBUTE|HAVE_ENDIAN_H|HAVE_EVHTTP_CONNECTION_GET_PEER_CONST_CHAR|HAVE_FDATASYNC|HAVE_GETENTROPY_RAND|HAVE_GETRANDOM|HAVE_GMTIME_R|HAVE_INTTYPES_H|HAVE_LIBADVAPI32|HAVE_LIBCOMCTL32|HAVE_LIBCOMDLG32|HAVE_LIBGDI32|HAVE_LIBIPHLPAPI|HAVE_LIBKERNEL32|HAVE_LIBOLE32|HAVE_LIBOLEAUT32|HAVE_LIBSHELL32|HAVE_LIBSHLWAPI|HAVE_LIBUSER32|HAVE_LIBUUID|HAVE_LIBWINMM|HAVE_LIBWS2_32|HAVE_MALLOC_INFO|HAVE_MALLOPT_ARENA_MAX|HAVE_MINIUPNPC_MINIUPNPC_H|HAVE_MINIUPNPC_UPNPCOMMANDS_H|HAVE_MINIUPNPC_UPNPERRORS_H|HAVE_NATPMP_H|HAVE_O_CLOEXEC|HAVE_POSIX_FALLOCATE|HAVE_PTHREAD|HAVE_PTHREAD_PRIO_INHERIT|HAVE_STDINT_H|HAVE_STDIO_H|HAVE_STDLIB_H|HAVE_STRERROR_R|HAVE_STRINGS_H|HAVE_STRING_H|HAVE_STRONG_GETAUXVAL|HAVE_SYSCTL|HAVE_SYSCTL_ARND|HAVE_SYSTEM|HAVE_SYS_ENDIAN_H|HAVE_SYS_PRCTL_H|HAVE_SYS_RESOURCES_H|HAVE_SYS_SELECT_H|HAVE_SYS_STAT_H|HAVE_SYS_SYSCTL_H|HAVE_SYS_TYPES_H|HAVE_SYS_VMMETER_H|HAVE_THREAD_LOCAL|HAVE_TIMINGSAFE_BCMP|HAVE_UNISTD_H|HAVE_VM_VM_PARAM_H|LT_OBJDIR|PACKAGE_BUGREPORT|PACKAGE_NAME|PACKAGE_STRING|PACKAGE_TARNAME|PACKAGE_URL|PACKAGE_VERSION|PTHREAD_CREATE_JOINABLE|QT_QPA_PLATFORM_ANDROID|QT_QPA_PLATFORM_COCOA|QT_QPA_PLATFORM_MINIMAL|QT_QPA_PLATFORM_WINDOWS|QT_QPA_PLATFORM_XCB|QT_STATICPLUGIN|STDC_HEADERS|STRERROR_R_CHAR_P|USE_ASM|USE_BDB|USE_DBUS|USE_NATPMP|USE_QRCODE|USE_SQLITE|USE_UPNP|_FILE_OFFSET_BITS|_LARGE_FILES)'
exclusion_files=":(exclude)src/minisketch :(exclude)src/crc32c :(exclude)src/secp256k1 :(exclude)src/crypto/sha256_arm_shani.cpp :(exclude)src/crypto/sha256_avx2.cpp :(exclude)src/crypto/sha256_sse41.cpp :(exclude)src/crypto/sha256_x86_shani.cpp"
git grep --perl-regexp --files-with-matches "$regex_string" -- '*.cpp' $exclusion_files | xargs git grep -L "bitcoin-config.h" | while read -r file; do line_number=$(awk -v my_file="$file" '/\/\/ file COPYING or https?:\/\/www.opensource.org\/licenses\/mit-license.php\./ {line = NR} /^\/\// && NR == line + 1 {while(getline && /^\/\//) line = NR} END {print line+1}' "$file"); sed -i "${line_number}i\\\\n\#if defined(HAVE_CONFIG_H)\\n#include <config/bitcoin-config.h>\\n\#endif" "$file"; done;
git grep --perl-regexp --files-with-matches "$regex_string" -- '*.h' $exclusion_files | xargs git grep -L "bitcoin-config.h" | while read -r file; do sed -i "/#define.*_H/a \\\\n\#if defined(HAVE_CONFIG_H)\\n#include <config/bitcoin-config.h>\\n\#endif" "$file"; done;
for file in $(git grep --files-with-matches 'bitcoin-config.h' -- '*.cpp' '*.h' $exclusion_files); do if ! grep -q --perl-regexp "$regex_string" $file; then sed -i '/HAVE_CONFIG_H/{N;N;N;d;}' $file; fi; done;
-END VERIFY SCRIPT-
The first command creates a regular expression for matching all bitcoin-config.h symbols in the following form: ^(?!//).*(AC_APPLE_UNIVERSAL_BUILD|BOOST_PROCESS_USE_STD_FS|...|_LARGE_FILES). It was generated with:
./autogen.sh && printf '^(?!//).*(%s)' $(awk '/^#undef/ {print $2}' src/config/bitcoin-config.h.in | paste -sd "|" -)
The second command holds a list of files and directories that should not be processed. These include subtree directories as well as some crypto files that already get their symbols through the makefile.
The third command checks for missing bitcoin-config headers in .cpp files and adds the header if it is missing.
The fourth command checks for missing bitcoin-config headers in .h files and adds the header if it is missing.
The fifth command checks for unneeded bitcoin-config headers in sources files and removes the header if it is unneeded.
247 lines
6.8 KiB
C++
247 lines
6.8 KiB
C++
// Copyright (c) 2011-2022 The Bitcoin Core developers
|
|
// Distributed under the MIT software license, see the accompanying
|
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|
|
|
#if defined(HAVE_CONFIG_H)
|
|
#include <config/bitcoin-config.h>
|
|
#endif
|
|
|
|
#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 <QDBusMetaType>
|
|
#include <QtDBus>
|
|
#include <stdint.h>
|
|
#endif
|
|
#ifdef Q_OS_MACOS
|
|
#include <qt/macnotificationhandler.h>
|
|
#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),
|
|
trayIcon(_trayIcon)
|
|
{
|
|
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_MACOS
|
|
// 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 https://www.qtcentre.org/archive/index.php/t-25879.html
|
|
class FreedesktopImage
|
|
{
|
|
public:
|
|
FreedesktopImage() = default;
|
|
explicit FreedesktopImage(const QImage &img);
|
|
|
|
// 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<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;
|
|
}
|
|
|
|
QVariant FreedesktopImage::toVariant(const QImage &img)
|
|
{
|
|
FreedesktopImage fimg(img);
|
|
return QVariant(qDBusRegisterMetaType<FreedesktopImage>(), &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);
|
|
}
|
|
#endif
|
|
|
|
void 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_MACOS
|
|
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, millisTimeout);
|
|
break;
|
|
#ifdef Q_OS_MACOS
|
|
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;
|
|
}
|
|
}
|