diff --git a/src/qt/csvmodelwriter.cpp b/src/qt/csvmodelwriter.cpp index 1c335478f..95e7154d1 100644 --- a/src/qt/csvmodelwriter.cpp +++ b/src/qt/csvmodelwriter.cpp @@ -1,76 +1,76 @@ // Copyright (c) 2011-2016 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 "csvmodelwriter.h" +#include #include #include #include CSVModelWriter::CSVModelWriter(const QString &_filename, QObject *parent) : QObject(parent), filename(_filename), model(0) {} void CSVModelWriter::setModel(const QAbstractItemModel *_model) { this->model = _model; } void CSVModelWriter::addColumn(const QString &title, int column, int role) { Column col; col.title = title; col.column = column; col.role = role; columns.append(col); } static void writeValue(QTextStream &f, const QString &value) { QString escaped = value; escaped.replace('"', "\"\""); f << "\"" << escaped << "\""; } static void writeSep(QTextStream &f) { f << ","; } static void writeNewline(QTextStream &f) { f << "\n"; } bool CSVModelWriter::write() { QFile file(filename); if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) return false; QTextStream out(&file); int numRows = 0; if (model) { numRows = model->rowCount(); } // Header row for (int i = 0; i < columns.size(); ++i) { if (i != 0) { writeSep(out); } writeValue(out, columns[i].title); } writeNewline(out); // Data rows for (int j = 0; j < numRows; ++j) { for (int i = 0; i < columns.size(); ++i) { if (i != 0) { writeSep(out); } QVariant data = model->index(j, columns[i].column).data(columns[i].role); writeValue(out, data.toString()); } writeNewline(out); } file.close(); return file.error() == QFile::NoError; } diff --git a/src/qt/intro.cpp b/src/qt/intro.cpp index b488e1259..16eab1020 100644 --- a/src/qt/intro.cpp +++ b/src/qt/intro.cpp @@ -1,309 +1,309 @@ // Copyright (c) 2011-2016 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" +#include #endif -#include "fs.h" -#include "guiutil.h" -#include "interfaces/node.h" -#include "intro.h" -#include "ui_intro.h" -#include "util.h" +#include +#include +#include +#include +#include +#include #include #include #include #include static const uint64_t GB_BYTES = 1000000000LL; /** * Minimum free space (in GB) needed for data directory. */ static const uint64_t BLOCK_CHAIN_SIZE = 200; /** * Minimum free space (in GB) needed for data directory when pruned; Does not * include prune target. */ static const uint64_t CHAIN_STATE_SIZE = 4; /** * Total required space (in GB) depending on user choice (prune, not prune). */ static uint64_t requiredSpace; /* Check free space asynchronously to prevent hanging the UI thread. Up to one request to check a path is in flight to this thread; when the check() function runs, the current path is requested from the associated Intro object. The reply is sent back through a signal. This ensures that no queue of checking requests is built up while the user is still entering the path, and that always the most recently entered path is checked as soon as the thread becomes available. */ class FreespaceChecker : public QObject { Q_OBJECT public: explicit FreespaceChecker(Intro *intro); enum Status { ST_OK, ST_ERROR }; public Q_SLOTS: void check(); Q_SIGNALS: void reply(int status, const QString &message, quint64 available); private: Intro *intro; }; #include "intro.moc" FreespaceChecker::FreespaceChecker(Intro *_intro) { this->intro = _intro; } void FreespaceChecker::check() { QString dataDirStr = intro->getPathToCheck(); fs::path dataDir = GUIUtil::qstringToBoostPath(dataDirStr); uint64_t freeBytesAvailable = 0; int replyStatus = ST_OK; QString replyMessage = tr("A new data directory will be created."); /* Find first parent that exists, so that fs::space does not fail */ fs::path parentDir = dataDir; fs::path parentDirOld = fs::path(); while (parentDir.has_parent_path() && !fs::exists(parentDir)) { parentDir = parentDir.parent_path(); /* Check if we make any progress, break if not to prevent an infinite * loop here */ if (parentDirOld == parentDir) break; parentDirOld = parentDir; } try { freeBytesAvailable = fs::space(parentDir).available; if (fs::exists(dataDir)) { if (fs::is_directory(dataDir)) { QString separator = "" + QDir::toNativeSeparators("/") + tr("name") + ""; replyStatus = ST_OK; replyMessage = tr("Directory already exists. Add %1 if you " "intend to create a new directory here.") .arg(separator); } else { replyStatus = ST_ERROR; replyMessage = tr("Path already exists, and is not a directory."); } } } catch (const fs::filesystem_error &) { /* Parent directory does not exist or is not accessible */ replyStatus = ST_ERROR; replyMessage = tr("Cannot create data directory here."); } Q_EMIT reply(replyStatus, replyMessage, freeBytesAvailable); } Intro::Intro(QWidget *parent) : QDialog(parent), ui(new Ui::Intro), thread(0), signalled(false) { ui->setupUi(this); ui->welcomeLabel->setText(ui->welcomeLabel->text().arg(tr(PACKAGE_NAME))); ui->storageLabel->setText(ui->storageLabel->text().arg(tr(PACKAGE_NAME))); uint64_t pruneTarget = std::max(0, gArgs.GetArg("-prune", 0)); requiredSpace = BLOCK_CHAIN_SIZE; if (pruneTarget) { uint64_t prunedGBs = std::ceil(pruneTarget * 1024 * 1024.0 / GB_BYTES); if (prunedGBs <= requiredSpace) { requiredSpace = prunedGBs; } } requiredSpace += CHAIN_STATE_SIZE; ui->sizeWarningLabel->setText( ui->sizeWarningLabel->text().arg(tr(PACKAGE_NAME)).arg(requiredSpace)); startThread(); } Intro::~Intro() { delete ui; /* Ensure thread is finished before it is deleted */ Q_EMIT stopThread(); thread->wait(); } QString Intro::getDataDirectory() { return ui->dataDirectory->text(); } void Intro::setDataDirectory(const QString &dataDir) { ui->dataDirectory->setText(dataDir); if (dataDir == getDefaultDataDirectory()) { ui->dataDirDefault->setChecked(true); ui->dataDirectory->setEnabled(false); ui->ellipsisButton->setEnabled(false); } else { ui->dataDirCustom->setChecked(true); ui->dataDirectory->setEnabled(true); ui->ellipsisButton->setEnabled(true); } } QString Intro::getDefaultDataDirectory() { return GUIUtil::boostPathToQString(GetDefaultDataDir()); } bool Intro::pickDataDirectory(interfaces::Node &node) { QSettings settings; /* If data directory provided on command line, no need to look at settings or show a picking dialog */ if (!gArgs.GetArg("-datadir", "").empty()) return true; /* 1) Default data directory for operating system */ QString dataDir = getDefaultDataDirectory(); /* 2) Allow QSettings to override default dir */ dataDir = settings.value("strDataDir", dataDir).toString(); if (!fs::exists(GUIUtil::qstringToBoostPath(dataDir)) || gArgs.GetBoolArg("-choosedatadir", DEFAULT_CHOOSE_DATADIR) || settings.value("fReset", false).toBool() || gArgs.GetBoolArg("-resetguisettings", false)) { /* If current default data directory does not exist, let the user choose * one */ Intro intro; intro.setDataDirectory(dataDir); intro.setWindowIcon(QIcon(":icons/bitcoin")); while (true) { if (!intro.exec()) { /* Cancel clicked */ return false; } dataDir = intro.getDataDirectory(); try { if (TryCreateDirectories( GUIUtil::qstringToBoostPath(dataDir))) { // If a new data directory has been created, make wallets // subdirectory too TryCreateDirectories(GUIUtil::qstringToBoostPath(dataDir) / "wallets"); } break; } catch (const fs::filesystem_error &) { QMessageBox::critical(0, tr(PACKAGE_NAME), tr("Error: Specified data directory " "\"%1\" cannot be created.") .arg(dataDir)); /* fall through, back to choosing screen */ } } settings.setValue("strDataDir", dataDir); settings.setValue("fReset", false); } /* Only override -datadir if different from the default, to make it possible * to * override -datadir in the bitcoin.conf file in the default data directory * (to be consistent with bitcoind behavior) */ if (dataDir != getDefaultDataDirectory()) { // use OS locale for path setting node.softSetArg("-datadir", GUIUtil::qstringToBoostPath(dataDir).string()); } return true; } void Intro::setStatus(int status, const QString &message, quint64 bytesAvailable) { switch (status) { case FreespaceChecker::ST_OK: ui->errorMessage->setText(message); ui->errorMessage->setStyleSheet(""); break; case FreespaceChecker::ST_ERROR: ui->errorMessage->setText(tr("Error") + ": " + message); ui->errorMessage->setStyleSheet("QLabel { color: #800000 }"); break; } /* Indicate number of bytes available */ if (status == FreespaceChecker::ST_ERROR) { ui->freeSpace->setText(""); } else { QString freeString = tr("%n GB of free space available", "", bytesAvailable / GB_BYTES); if (bytesAvailable < requiredSpace * GB_BYTES) { freeString += " " + tr("(of %n GB needed)", "", requiredSpace); ui->freeSpace->setStyleSheet("QLabel { color: #800000 }"); } else { ui->freeSpace->setStyleSheet(""); } ui->freeSpace->setText(freeString + "."); } /* Don't allow confirm in ERROR state */ ui->buttonBox->button(QDialogButtonBox::Ok) ->setEnabled(status != FreespaceChecker::ST_ERROR); } void Intro::on_dataDirectory_textChanged(const QString &dataDirStr) { /* Disable OK button until check result comes in */ ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); checkPath(dataDirStr); } void Intro::on_ellipsisButton_clicked() { QString dir = QDir::toNativeSeparators(QFileDialog::getExistingDirectory( 0, "Choose data directory", ui->dataDirectory->text())); if (!dir.isEmpty()) ui->dataDirectory->setText(dir); } void Intro::on_dataDirDefault_clicked() { setDataDirectory(getDefaultDataDirectory()); } void Intro::on_dataDirCustom_clicked() { ui->dataDirectory->setEnabled(true); ui->ellipsisButton->setEnabled(true); } void Intro::startThread() { thread = new QThread(this); FreespaceChecker *executor = new FreespaceChecker(this); executor->moveToThread(thread); connect(executor, SIGNAL(reply(int, QString, quint64)), this, SLOT(setStatus(int, QString, quint64))); connect(this, SIGNAL(requestCheck()), executor, SLOT(check())); /* make sure executor object is deleted in its own thread */ connect(this, SIGNAL(stopThread()), executor, SLOT(deleteLater())); connect(this, SIGNAL(stopThread()), thread, SLOT(quit())); thread->start(); } void Intro::checkPath(const QString &dataDir) { mutex.lock(); pathToCheck = dataDir; if (!signalled) { signalled = true; Q_EMIT requestCheck(); } mutex.unlock(); } QString Intro::getPathToCheck() { QString retval; mutex.lock(); retval = pathToCheck; signalled = false; /* new request can be queued now */ mutex.unlock(); return retval; } diff --git a/src/qt/modaloverlay.cpp b/src/qt/modaloverlay.cpp index c0c96c5ba..e1a44801b 100644 --- a/src/qt/modaloverlay.cpp +++ b/src/qt/modaloverlay.cpp @@ -1,166 +1,165 @@ // Copyright (c) 2016 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 "modaloverlay.h" -#include "ui_modaloverlay.h" +#include +#include -#include "guiutil.h" - -#include "chainparams.h" +#include +#include #include #include ModalOverlay::ModalOverlay(QWidget *parent) : QWidget(parent), ui(new Ui::ModalOverlay), bestHeaderHeight(0), bestHeaderDate(QDateTime()), layerIsVisible(false), userClosed(false) { ui->setupUi(this); connect(ui->closeButton, SIGNAL(clicked()), this, SLOT(closeClicked())); if (parent) { parent->installEventFilter(this); raise(); } blockProcessTime.clear(); setVisible(false); } ModalOverlay::~ModalOverlay() { delete ui; } bool ModalOverlay::eventFilter(QObject *obj, QEvent *ev) { if (obj == parent()) { if (ev->type() == QEvent::Resize) { QResizeEvent *rev = static_cast(ev); resize(rev->size()); if (!layerIsVisible) setGeometry(0, height(), width(), height()); } else if (ev->type() == QEvent::ChildAdded) { raise(); } } return QWidget::eventFilter(obj, ev); } //! Tracks parent widget changes bool ModalOverlay::event(QEvent *ev) { if (ev->type() == QEvent::ParentAboutToChange) { if (parent()) parent()->removeEventFilter(this); } else if (ev->type() == QEvent::ParentChange) { if (parent()) { parent()->installEventFilter(this); raise(); } } return QWidget::event(ev); } void ModalOverlay::setKnownBestHeight(int count, const QDateTime &blockDate) { if (count > bestHeaderHeight) { bestHeaderHeight = count; bestHeaderDate = blockDate; } } void ModalOverlay::tipUpdate(int count, const QDateTime &blockDate, double nVerificationProgress) { QDateTime currentDate = QDateTime::currentDateTime(); // keep a vector of samples of verification progress at height blockProcessTime.push_front( qMakePair(currentDate.toMSecsSinceEpoch(), nVerificationProgress)); // show progress speed if we have more then one sample if (blockProcessTime.size() >= 2) { double progressStart = blockProcessTime[0].second; double progressDelta = 0; double progressPerHour = 0; qint64 timeDelta = 0; qint64 remainingMSecs = 0; double remainingProgress = 1.0 - nVerificationProgress; for (int i = 1; i < blockProcessTime.size(); i++) { QPair sample = blockProcessTime[i]; // take first sample after 500 seconds or last available one if (sample.first < (currentDate.toMSecsSinceEpoch() - 500 * 1000) || i == blockProcessTime.size() - 1) { progressDelta = progressStart - sample.second; timeDelta = blockProcessTime[0].first - sample.first; progressPerHour = progressDelta / (double)timeDelta * 1000 * 3600; remainingMSecs = remainingProgress / progressDelta * timeDelta; break; } } // show progress increase per hour ui->progressIncreasePerH->setText( QString::number(progressPerHour * 100, 'f', 2) + "%"); // show expected remaining time ui->expectedTimeLeft->setText( GUIUtil::formatNiceTimeOffset(remainingMSecs / 1000.0)); static const int MAX_SAMPLES = 5000; if (blockProcessTime.count() > MAX_SAMPLES) blockProcessTime.remove(MAX_SAMPLES, blockProcessTime.count() - MAX_SAMPLES); } // show the last block date ui->newestBlockDate->setText(blockDate.toString()); // show the percentage done according to nVerificationProgress ui->percentageProgress->setText( QString::number(nVerificationProgress * 100, 'f', 2) + "%"); ui->progressBar->setValue(nVerificationProgress * 100); if (!bestHeaderDate.isValid()) // not syncing return; // estimate the number of headers left based on nPowTargetSpacing // and check if the gui is not aware of the the best header (happens rarely) int estimateNumHeadersLeft = bestHeaderDate.secsTo(currentDate) / Params().GetConsensus().nPowTargetSpacing; bool hasBestHeader = bestHeaderHeight >= count; // show remaining number of blocks if (estimateNumHeadersLeft < HEADER_HEIGHT_DELTA_SYNC && hasBestHeader) { ui->numberOfBlocksLeft->setText( QString::number(bestHeaderHeight - count)); } else { ui->numberOfBlocksLeft->setText( tr("Unknown. Syncing Headers (%1)...").arg(bestHeaderHeight)); ui->expectedTimeLeft->setText(tr("Unknown...")); } } void ModalOverlay::toggleVisibility() { showHide(layerIsVisible, true); if (!layerIsVisible) userClosed = true; } void ModalOverlay::showHide(bool hide, bool userRequested) { if ((layerIsVisible && !hide) || (!layerIsVisible && hide) || (!hide && userClosed && !userRequested)) return; if (!isVisible() && !hide) setVisible(true); setGeometry(0, hide ? 0 : height(), width(), height()); QPropertyAnimation *animation = new QPropertyAnimation(this, "pos"); animation->setDuration(300); animation->setStartValue(QPoint(0, hide ? 0 : this->height())); animation->setEndValue(QPoint(0, hide ? this->height() : 0)); animation->setEasingCurve(QEasingCurve::OutQuad); animation->start(QAbstractAnimation::DeleteWhenStopped); layerIsVisible = !hide; } void ModalOverlay::closeClicked() { showHide(true); userClosed = true; } diff --git a/src/qt/networkstyle.cpp b/src/qt/networkstyle.cpp index 7967be333..7854d3414 100644 --- a/src/qt/networkstyle.cpp +++ b/src/qt/networkstyle.cpp @@ -1,86 +1,86 @@ // Copyright (c) 2014-2016 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 "networkstyle.h" +#include -#include "guiconstants.h" +#include #include static const struct { const char *networkId; const char *appName; const int iconColorHueShift; const int iconColorSaturationReduction; const char *titleAddText; } network_styles[] = {{"main", QAPP_APP_NAME_DEFAULT, 0, 0, ""}, {"test", QAPP_APP_NAME_TESTNET, 70, 30, QT_TRANSLATE_NOOP("SplashScreen", "[testnet]")}, {"regtest", QAPP_APP_NAME_TESTNET, 160, 30, "[regtest]"}}; static const unsigned network_styles_count = sizeof(network_styles) / sizeof(*network_styles); // titleAddText needs to be const char* for tr() NetworkStyle::NetworkStyle(const QString &_appName, const int iconColorHueShift, const int iconColorSaturationReduction, const char *_titleAddText) : appName(_appName), titleAddText(qApp->translate("SplashScreen", _titleAddText)) { // load pixmap QPixmap pixmap(":/icons/bitcoin"); if (iconColorHueShift != 0 && iconColorSaturationReduction != 0) { // generate QImage from QPixmap QImage img = pixmap.toImage(); int h, s, l, a; // traverse though lines for (int y = 0; y < img.height(); y++) { QRgb *scL = reinterpret_cast(img.scanLine(y)); // loop through pixels for (int x = 0; x < img.width(); x++) { // preserve alpha because QColor::getHsl doesen't return the // alpha value a = qAlpha(scL[x]); QColor col(scL[x]); // get hue value col.getHsl(&h, &s, &l); // rotate color on RGB color circle // 70° should end up with the typical "testnet" green h += iconColorHueShift; // change saturation value if (s > iconColorSaturationReduction) { s -= iconColorSaturationReduction; } col.setHsl(h, s, l, a); // set the pixel scL[x] = col.rgba(); } } // convert back to QPixmap pixmap.convertFromImage(img); } appIcon = QIcon(pixmap); trayAndWindowIcon = QIcon(pixmap.scaled(QSize(256, 256))); } const NetworkStyle *NetworkStyle::instantiate(const QString &networkId) { for (unsigned x = 0; x < network_styles_count; ++x) { if (networkId == network_styles[x].networkId) { return new NetworkStyle( network_styles[x].appName, network_styles[x].iconColorHueShift, network_styles[x].iconColorSaturationReduction, network_styles[x].titleAddText); } } return 0; } diff --git a/src/qt/notificator.cpp b/src/qt/notificator.cpp index e2ff1b18f..8592eecb4 100644 --- a/src/qt/notificator.cpp +++ b/src/qt/notificator.cpp @@ -1,268 +1,268 @@ // Copyright (c) 2011-2016 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 "notificator.h" +#include #include #include #include #include #include #include #include #include #include #include #ifdef USE_DBUS #include #include #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 "macnotificationhandler.h" #include +#include #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), mode(None), trayIcon(_trayIcon) #ifdef USE_DBUS , interface(0) #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.html class 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 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(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(); } 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) { Q_UNUSED(cls); // Arguments for DBus call: QList args; // Program Name: args.append(programName); // Unique ID of this notification type: 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, const QIcon &icon, int millisTimeout) { Q_UNUSED(icon); 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); } // Based on Qt's tray icon implementation #ifdef Q_OS_MAC void Notificator::notifyMacUserNotificationCenter(Class cls, const QString &title, const QString &text, const QIcon &icon) { // 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, icon, millisTimeout); break; #ifdef Q_OS_MAC case UserNotificationCenter: notifyMacUserNotificationCenter(cls, title, text, icon); 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; } } diff --git a/src/qt/notificator.h b/src/qt/notificator.h index 361d8755e..d9ddba29a 100644 --- a/src/qt/notificator.h +++ b/src/qt/notificator.h @@ -1,84 +1,84 @@ // Copyright (c) 2011-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_QT_NOTIFICATOR_H #define BITCOIN_QT_NOTIFICATOR_H #if defined(HAVE_CONFIG_H) -#include "config/bitcoin-config.h" +#include #endif #include #include QT_BEGIN_NAMESPACE class QSystemTrayIcon; #ifdef USE_DBUS class QDBusInterface; #endif QT_END_NAMESPACE /** Cross-platform desktop notification client. */ class Notificator : public QObject { Q_OBJECT public: /** Create a new notificator. @note Ownership of trayIcon is not transferred to this object. */ Notificator(const QString &programName, QSystemTrayIcon *trayIcon, QWidget *parent); ~Notificator(); // Message class enum Class { Information, /**< Informational message */ Warning, /**< Notify user of potential problem */ Critical /**< An error occurred */ }; public Q_SLOTS: /** Show notification message. @param[in] cls general message class @param[in] title title shown with message @param[in] text message content @param[in] icon optional icon to show with message @param[in] millisTimeout notification timeout in milliseconds (defaults to 10 seconds) @note Platform implementations are free to ignore any of the provided fields except for \a text. */ void notify(Class cls, const QString &title, const QString &text, const QIcon &icon = QIcon(), int millisTimeout = 10000); private: QWidget *parent; enum Mode { None, /**< Ignore informational notifications, and show a modal pop-up dialog for Critical notifications. */ Freedesktop, /**< Use DBus org.freedesktop.Notifications */ QSystemTray, /**< Use QSystemTray::showMessage */ UserNotificationCenter /**< Use the 10.8+ User Notification Center (Mac only) */ }; QString programName; Mode mode; QSystemTrayIcon *trayIcon; #ifdef USE_DBUS QDBusInterface *interface; void notifyDBus(Class cls, const QString &title, const QString &text, const QIcon &icon, int millisTimeout); #endif void notifySystray(Class cls, const QString &title, const QString &text, const QIcon &icon, int millisTimeout); #ifdef Q_OS_MAC void notifyMacUserNotificationCenter(Class cls, const QString &title, const QString &text, const QIcon &icon); #endif }; #endif // BITCOIN_QT_NOTIFICATOR_H diff --git a/src/qt/paymentrequestplus.cpp b/src/qt/paymentrequestplus.cpp index b9f8c5836..3e14e5090 100644 --- a/src/qt/paymentrequestplus.cpp +++ b/src/qt/paymentrequestplus.cpp @@ -1,235 +1,235 @@ // Copyright (c) 2011-2016 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. // // Wraps dumb protocol buffer paymentRequest with some extra methods // -#include "paymentrequestplus.h" +#include -#include "util.h" - -#include +#include #include #include #include #include +#include + class SSLVerifyError : public std::runtime_error { public: explicit SSLVerifyError(std::string err) : std::runtime_error(err) {} }; bool PaymentRequestPlus::parse(const QByteArray &data) { bool parseOK = paymentRequest.ParseFromArray(data.data(), data.size()); if (!parseOK) { qWarning() << "PaymentRequestPlus::parse: Error parsing payment request"; return false; } if (paymentRequest.payment_details_version() > 1) { qWarning() << "PaymentRequestPlus::parse: Received up-version payment " "details, version=" << paymentRequest.payment_details_version(); return false; } parseOK = details.ParseFromString(paymentRequest.serialized_payment_details()); if (!parseOK) { qWarning() << "PaymentRequestPlus::parse: Error parsing payment details"; paymentRequest.Clear(); return false; } return true; } bool PaymentRequestPlus::SerializeToString(std::string *output) const { return paymentRequest.SerializeToString(output); } bool PaymentRequestPlus::IsInitialized() const { return paymentRequest.IsInitialized(); } bool PaymentRequestPlus::getMerchant(X509_STORE *certStore, QString &merchant) const { merchant.clear(); if (!IsInitialized()) return false; // One day we'll support more PKI types, but just x509 for now: const EVP_MD *digestAlgorithm = nullptr; if (paymentRequest.pki_type() == "x509+sha256") { digestAlgorithm = EVP_sha256(); } else if (paymentRequest.pki_type() == "x509+sha1") { digestAlgorithm = EVP_sha1(); } else if (paymentRequest.pki_type() == "none") { qWarning() << "PaymentRequestPlus::getMerchant: Payment request: " "pki_type == none"; return false; } else { qWarning() << "PaymentRequestPlus::getMerchant: Payment request: " "unknown pki_type " << QString::fromStdString(paymentRequest.pki_type()); return false; } payments::X509Certificates certChain; if (!certChain.ParseFromString(paymentRequest.pki_data())) { qWarning() << "PaymentRequestPlus::getMerchant: Payment request: error " "parsing pki_data"; return false; } std::vector certs; const QDateTime currentTime = QDateTime::currentDateTime(); for (int i = 0; i < certChain.certificate_size(); i++) { QByteArray certData(certChain.certificate(i).data(), certChain.certificate(i).size()); QSslCertificate qCert(certData, QSsl::Der); if (currentTime < qCert.effectiveDate() || currentTime > qCert.expiryDate()) { qWarning() << "PaymentRequestPlus::getMerchant: Payment request: " "certificate expired or not yet active: " << qCert; return false; } if (qCert.isBlacklisted()) { qWarning() << "PaymentRequestPlus::getMerchant: Payment request: " "certificate blacklisted: " << qCert; return false; } const uint8_t *data = (const uint8_t *)certChain.certificate(i).data(); X509 *cert = d2i_X509(nullptr, &data, certChain.certificate(i).size()); if (cert) certs.push_back(cert); } if (certs.empty()) { qWarning() << "PaymentRequestPlus::getMerchant: Payment request: empty " "certificate chain"; return false; } // The first cert is the signing cert, the rest are untrusted certs that // chain to a valid root authority. OpenSSL needs them separately. STACK_OF(X509) *chain = sk_X509_new_null(); for (int i = certs.size() - 1; i > 0; i--) { sk_X509_push(chain, certs[i]); } X509 *signing_cert = certs[0]; // Now create a "store context", which is a single use object for checking, // load the signing cert into it and verify. X509_STORE_CTX *store_ctx = X509_STORE_CTX_new(); if (!store_ctx) { qWarning() << "PaymentRequestPlus::getMerchant: Payment request: error " "creating X509_STORE_CTX"; return false; } char *website = nullptr; bool fResult = true; try { if (!X509_STORE_CTX_init(store_ctx, certStore, signing_cert, chain)) { int error = X509_STORE_CTX_get_error(store_ctx); throw SSLVerifyError(X509_verify_cert_error_string(error)); } // Now do the verification! int result = X509_verify_cert(store_ctx); if (result != 1) { int error = X509_STORE_CTX_get_error(store_ctx); // For testing payment requests, we allow self signed root certs! // This option is just shown in the UI options, if -help-debug is // enabled. if (!(error == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT && gArgs.GetBoolArg("-allowselfsignedrootcertificates", DEFAULT_SELFSIGNED_ROOTCERTS))) { throw SSLVerifyError(X509_verify_cert_error_string(error)); } else { qDebug() << "PaymentRequestPlus::getMerchant: Allowing self " "signed root certificate, because " "-allowselfsignedrootcertificates is true."; } } X509_NAME *certname = X509_get_subject_name(signing_cert); // Valid cert; check signature: // Copy payments::PaymentRequest rcopy(paymentRequest); rcopy.set_signature(std::string("")); // Everything but the signature std::string data_to_verify; rcopy.SerializeToString(&data_to_verify); #if HAVE_DECL_EVP_MD_CTX_NEW EVP_MD_CTX *ctx = EVP_MD_CTX_new(); if (!ctx) throw SSLVerifyError("Error allocating OpenSSL context."); #else EVP_MD_CTX _ctx; EVP_MD_CTX *ctx; ctx = &_ctx; #endif EVP_PKEY *pubkey = X509_get_pubkey(signing_cert); EVP_MD_CTX_init(ctx); if (!EVP_VerifyInit_ex(ctx, digestAlgorithm, nullptr) || !EVP_VerifyUpdate(ctx, data_to_verify.data(), data_to_verify.size()) || !EVP_VerifyFinal( ctx, (const uint8_t *)paymentRequest.signature().data(), (unsigned int)paymentRequest.signature().size(), pubkey)) { throw SSLVerifyError("Bad signature, invalid payment request."); } #if HAVE_DECL_EVP_MD_CTX_NEW EVP_MD_CTX_free(ctx); #endif // OpenSSL API for getting human printable strings from certs is // baroque. int textlen = X509_NAME_get_text_by_NID(certname, NID_commonName, nullptr, 0); website = new char[textlen + 1]; if (X509_NAME_get_text_by_NID(certname, NID_commonName, website, textlen + 1) == textlen && textlen > 0) { merchant = website; } else { throw SSLVerifyError("Bad certificate, missing common name."); } // TODO: detect EV certificates and set merchant = business name instead // of unfriendly NID_commonName ? } catch (const SSLVerifyError &err) { fResult = false; qWarning() << "PaymentRequestPlus::getMerchant: SSL error: " << err.what(); } if (website) { delete[] website; } X509_STORE_CTX_free(store_ctx); for (size_t i = 0; i < certs.size(); i++) { X509_free(certs[i]); } return fResult; } QList> PaymentRequestPlus::getPayTo() const { QList> result; for (int i = 0; i < details.outputs_size(); i++) { const uint8_t *scriptStr = (const uint8_t *)details.outputs(i).script().data(); CScript s(scriptStr, scriptStr + details.outputs(i).script().size()); result.append( std::make_pair(s, int64_t(details.outputs(i).amount()) * SATOSHI)); } return result; } diff --git a/src/qt/paymentrequestplus.h b/src/qt/paymentrequestplus.h index 9855550bf..6886ccbee 100644 --- a/src/qt/paymentrequestplus.h +++ b/src/qt/paymentrequestplus.h @@ -1,49 +1,49 @@ // Copyright (c) 2011-2016 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_QT_PAYMENTREQUESTPLUS_H #define BITCOIN_QT_PAYMENTREQUESTPLUS_H #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdeprecated-declarations" -#include "paymentrequest.pb.h" +#include #pragma GCC diagnostic pop -#include "base58.h" +#include #include #include #include #include static const bool DEFAULT_SELFSIGNED_ROOTCERTS = false; // // Wraps dumb protocol buffer paymentRequest with extra methods // class PaymentRequestPlus { public: PaymentRequestPlus() {} bool parse(const QByteArray &data); bool SerializeToString(std::string *output) const; bool IsInitialized() const; // Returns true if merchant's identity is authenticated, and returns // human-readable merchant identity in merchant bool getMerchant(X509_STORE *certStore, QString &merchant) const; // Returns list of outputs, amount QList> getPayTo() const; const payments::PaymentDetails &getDetails() const { return details; } private: payments::PaymentRequest paymentRequest; payments::PaymentDetails details; }; #endif // BITCOIN_QT_PAYMENTREQUESTPLUS_H diff --git a/src/qt/platformstyle.cpp b/src/qt/platformstyle.cpp index 86cb0298c..d2ba46993 100644 --- a/src/qt/platformstyle.cpp +++ b/src/qt/platformstyle.cpp @@ -1,126 +1,126 @@ // Copyright (c) 2015-2016 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 "platformstyle.h" +#include -#include "guiconstants.h" +#include #include #include #include #include #include #include static const struct { const char *platformId; /** Show images on push buttons */ const bool imagesOnButtons; /** Colorize single-color icons */ const bool colorizeIcons; /** Extra padding/spacing in transactionview */ const bool useExtraSpacing; } platform_styles[] = {{"macosx", false, false, true}, {"windows", true, false, false}, /* Other: linux, unix, ... */ {"other", true, true, false}}; static const unsigned platform_styles_count = sizeof(platform_styles) / sizeof(*platform_styles); namespace { /* Local functions for colorizing single-color images */ void MakeSingleColorImage(QImage &img, const QColor &colorbase) { img = img.convertToFormat(QImage::Format_ARGB32); for (int x = img.width(); x--;) { for (int y = img.height(); y--;) { const QRgb rgb = img.pixel(x, y); img.setPixel(x, y, qRgba(colorbase.red(), colorbase.green(), colorbase.blue(), qAlpha(rgb))); } } } QIcon ColorizeIcon(const QIcon &ico, const QColor &colorbase) { QIcon new_ico; for (QSize sz : ico.availableSizes()) { QImage img(ico.pixmap(sz).toImage()); MakeSingleColorImage(img, colorbase); new_ico.addPixmap(QPixmap::fromImage(img)); } return new_ico; } QImage ColorizeImage(const QString &filename, const QColor &colorbase) { QImage img(filename); MakeSingleColorImage(img, colorbase); return img; } QIcon ColorizeIcon(const QString &filename, const QColor &colorbase) { return QIcon(QPixmap::fromImage(ColorizeImage(filename, colorbase))); } } // namespace PlatformStyle::PlatformStyle(const QString &_name, bool _imagesOnButtons, bool _colorizeIcons, bool _useExtraSpacing) : name(_name), imagesOnButtons(_imagesOnButtons), colorizeIcons(_colorizeIcons), useExtraSpacing(_useExtraSpacing), singleColor(0, 0, 0), textColor(0, 0, 0) { // Determine icon highlighting color if (colorizeIcons) { const QColor colorHighlightBg( QApplication::palette().color(QPalette::Highlight)); const QColor colorHighlightFg( QApplication::palette().color(QPalette::HighlightedText)); const QColor colorText( QApplication::palette().color(QPalette::WindowText)); const int colorTextLightness = colorText.lightness(); QColor colorbase; if (abs(colorHighlightBg.lightness() - colorTextLightness) < abs(colorHighlightFg.lightness() - colorTextLightness)) colorbase = colorHighlightBg; else colorbase = colorHighlightFg; singleColor = colorbase; } // Determine text color textColor = QColor(QApplication::palette().color(QPalette::WindowText)); } QImage PlatformStyle::SingleColorImage(const QString &filename) const { if (!colorizeIcons) return QImage(filename); return ColorizeImage(filename, SingleColor()); } QIcon PlatformStyle::SingleColorIcon(const QString &filename) const { if (!colorizeIcons) return QIcon(filename); return ColorizeIcon(filename, SingleColor()); } QIcon PlatformStyle::SingleColorIcon(const QIcon &icon) const { if (!colorizeIcons) return icon; return ColorizeIcon(icon, SingleColor()); } QIcon PlatformStyle::TextColorIcon(const QString &filename) const { return ColorizeIcon(filename, TextColor()); } QIcon PlatformStyle::TextColorIcon(const QIcon &icon) const { return ColorizeIcon(icon, TextColor()); } const PlatformStyle *PlatformStyle::instantiate(const QString &platformId) { for (unsigned x = 0; x < platform_styles_count; ++x) { if (platformId == platform_styles[x].platformId) { return new PlatformStyle(platform_styles[x].platformId, platform_styles[x].imagesOnButtons, platform_styles[x].colorizeIcons, platform_styles[x].useExtraSpacing); } } return 0; } diff --git a/src/qt/transactionfilterproxy.cpp b/src/qt/transactionfilterproxy.cpp index 963f8f3bb..7d634321d 100644 --- a/src/qt/transactionfilterproxy.cpp +++ b/src/qt/transactionfilterproxy.cpp @@ -1,110 +1,110 @@ // Copyright (c) 2011-2016 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 "transactionfilterproxy.h" +#include -#include "transactionrecord.h" -#include "transactiontablemodel.h" - -#include +#include +#include #include +#include + // Earliest date that can be represented (far in the past) const QDateTime TransactionFilterProxy::MIN_DATE = QDateTime::fromTime_t(0); // Last date that can be represented (far in the future) const QDateTime TransactionFilterProxy::MAX_DATE = QDateTime::fromTime_t(0xFFFFFFFF); TransactionFilterProxy::TransactionFilterProxy(QObject *parent) : QSortFilterProxyModel(parent), dateFrom(MIN_DATE), dateTo(MAX_DATE), addrPrefix(), typeFilter(ALL_TYPES), watchOnlyFilter(WatchOnlyFilter_All), minAmount(), limitRows(-1), showInactive(true) {} bool TransactionFilterProxy::filterAcceptsRow( int sourceRow, const QModelIndex &sourceParent) const { QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent); int type = index.data(TransactionTableModel::TypeRole).toInt(); QDateTime datetime = index.data(TransactionTableModel::DateRole).toDateTime(); bool involvesWatchAddress = index.data(TransactionTableModel::WatchonlyRole).toBool(); QString address = index.data(TransactionTableModel::AddressRole).toString(); QString label = index.data(TransactionTableModel::LabelRole).toString(); Amount amount( int64_t( llabs(index.data(TransactionTableModel::AmountRole).toLongLong())) * SATOSHI); int status = index.data(TransactionTableModel::StatusRole).toInt(); if (!showInactive && status == TransactionStatus::Conflicted) { return false; } if (!(TYPE(type) & typeFilter)) { return false; } if (involvesWatchAddress && watchOnlyFilter == WatchOnlyFilter_No) { return false; } if (!involvesWatchAddress && watchOnlyFilter == WatchOnlyFilter_Yes) { return false; } if (datetime < dateFrom || datetime > dateTo) { return false; } if (!address.contains(addrPrefix, Qt::CaseInsensitive) && !label.contains(addrPrefix, Qt::CaseInsensitive)) { return false; } if (amount < minAmount) { return false; } return true; } void TransactionFilterProxy::setDateRange(const QDateTime &from, const QDateTime &to) { this->dateFrom = from; this->dateTo = to; invalidateFilter(); } void TransactionFilterProxy::setAddressPrefix(const QString &_addrPrefix) { this->addrPrefix = _addrPrefix; invalidateFilter(); } void TransactionFilterProxy::setTypeFilter(quint32 modes) { this->typeFilter = modes; invalidateFilter(); } void TransactionFilterProxy::setMinAmount(const Amount minimum) { this->minAmount = minimum; invalidateFilter(); } void TransactionFilterProxy::setWatchOnlyFilter(WatchOnlyFilter filter) { this->watchOnlyFilter = filter; invalidateFilter(); } void TransactionFilterProxy::setLimit(int limit) { this->limitRows = limit; } void TransactionFilterProxy::setShowInactive(bool _showInactive) { this->showInactive = _showInactive; invalidateFilter(); } int TransactionFilterProxy::rowCount(const QModelIndex &parent) const { if (limitRows != -1) { return std::min(QSortFilterProxyModel::rowCount(parent), limitRows); } else { return QSortFilterProxyModel::rowCount(parent); } } diff --git a/src/qt/transactionfilterproxy.h b/src/qt/transactionfilterproxy.h index 0f4c06edb..3339a96f7 100644 --- a/src/qt/transactionfilterproxy.h +++ b/src/qt/transactionfilterproxy.h @@ -1,79 +1,79 @@ // Copyright (c) 2011-2014 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_QT_TRANSACTIONFILTERPROXY_H #define BITCOIN_QT_TRANSACTIONFILTERPROXY_H -#include "amount.h" +#include #include #include /** * Filter the transaction list according to pre-specified rules. */ class TransactionFilterProxy : public QSortFilterProxyModel { Q_OBJECT public: explicit TransactionFilterProxy(QObject *parent = 0); /** * Earliest date that can be represented (far in the past). */ static const QDateTime MIN_DATE; /** * Last date that can be represented (far in the future). */ static const QDateTime MAX_DATE; /** * Type filter bit field (all types). */ static const quint32 ALL_TYPES = 0xFFFFFFFF; static quint32 TYPE(int type) { return 1 << type; } enum WatchOnlyFilter { WatchOnlyFilter_All, WatchOnlyFilter_Yes, WatchOnlyFilter_No }; void setDateRange(const QDateTime &from, const QDateTime &to); void setAddressPrefix(const QString &addrPrefix); /** * @note Type filter takes a bit field created with TYPE() or ALL_TYPES */ void setTypeFilter(quint32 modes); void setMinAmount(const Amount minimum); void setWatchOnlyFilter(WatchOnlyFilter filter); /** * Set maximum number of rows returned, -1 if unlimited. */ void setLimit(int limit); /** * Set whether to show conflicted transactions. */ void setShowInactive(bool showInactive); int rowCount(const QModelIndex &parent = QModelIndex()) const override; protected: bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override; private: QDateTime dateFrom; QDateTime dateTo; QString addrPrefix; quint32 typeFilter; WatchOnlyFilter watchOnlyFilter; Amount minAmount; int limitRows; bool showInactive; }; #endif // BITCOIN_QT_TRANSACTIONFILTERPROXY_H diff --git a/src/qt/winshutdownmonitor.cpp b/src/qt/winshutdownmonitor.cpp index 7962e6351..a3d62be0c 100644 --- a/src/qt/winshutdownmonitor.cpp +++ b/src/qt/winshutdownmonitor.cpp @@ -1,74 +1,75 @@ // Copyright (c) 2014-2016 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 "winshutdownmonitor.h" +#include #if defined(Q_OS_WIN) #include #include #include -#include #include +#include + // If we don't want a message to be processed by Qt, return true and set result // to the value that the window procedure should return. Otherwise return false. bool WinShutdownMonitor::nativeEventFilter(const QByteArray &eventType, void *pMessage, long *pnResult) { Q_UNUSED(eventType); MSG *pMsg = static_cast(pMessage); // Seed OpenSSL PRNG with Windows event data (e.g. mouse movements and // other user interactions) if (RAND_event(pMsg->message, pMsg->wParam, pMsg->lParam) == 0) { // Warn only once as this is performance-critical static bool warned = false; if (!warned) { LogPrintf("%s: OpenSSL RAND_event() failed to seed OpenSSL PRNG " "with enough data.\n", __func__); warned = true; } } switch (pMsg->message) { case WM_QUERYENDSESSION: { // Initiate a client shutdown after receiving a WM_QUERYENDSESSION // and block // Windows session end until we have finished client shutdown. StartShutdown(); *pnResult = FALSE; return true; } case WM_ENDSESSION: { *pnResult = FALSE; return true; } } return false; } void WinShutdownMonitor::registerShutdownBlockReason(const QString &strReason, const HWND &mainWinId) { typedef BOOL(WINAPI * PSHUTDOWNBRCREATE)(HWND, LPCWSTR); PSHUTDOWNBRCREATE shutdownBRCreate = (PSHUTDOWNBRCREATE)GetProcAddress( GetModuleHandleA("User32.dll"), "ShutdownBlockReasonCreate"); if (shutdownBRCreate == nullptr) { qWarning() << "registerShutdownBlockReason: GetProcAddress for " "ShutdownBlockReasonCreate failed"; return; } if (shutdownBRCreate(mainWinId, strReason.toStdWString().c_str())) qWarning() << "registerShutdownBlockReason: Successfully registered: " + strReason; else qWarning() << "registerShutdownBlockReason: Failed to register: " + strReason; } #endif