diff --git a/share/qt/Info.plist.cmake.in b/share/qt/Info.plist.cmake.in --- a/share/qt/Info.plist.cmake.in +++ b/share/qt/Info.plist.cmake.in @@ -97,9 +97,6 @@ NSHighResolutionCapable True - LSAppNapIsDisabled - True - LSApplicationCategoryType public.app-category.finance diff --git a/src/qt/CMakeLists.txt b/src/qt/CMakeLists.txt --- a/src/qt/CMakeLists.txt +++ b/src/qt/CMakeLists.txt @@ -140,6 +140,7 @@ target_sources(bitcoin-qt-base PRIVATE macdockiconhandler.mm macnotificationhandler.mm + macos_appnap.mm ) set_property(TARGET bitcoin-qt-base PROPERTY AUTOMOC_MOC_OPTIONS "-DQ_OS_MAC") diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h --- a/src/qt/bitcoingui.h +++ b/src/qt/bitcoingui.h @@ -20,6 +20,10 @@ #include #include +#ifdef Q_OS_MAC +#include +#endif + #include class ClientModel; @@ -170,6 +174,10 @@ HelpMessageDialog *helpMessageDialog = nullptr; ModalOverlay *modalOverlay = nullptr; +#ifdef Q_OS_MAC + CAppNapInhibitor *m_app_nap_inhibitor = nullptr; +#endif + /** Keep track of previous number of blocks, to detect progress */ int prevBlocks = 0; int spinnerFrame = 0; diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -208,6 +208,10 @@ &BitcoinGUI::showModalOverlay); } #endif + +#ifdef Q_OS_MAC + m_app_nap_inhibitor = new CAppNapInhibitor; +#endif } BitcoinGUI::~BitcoinGUI() { @@ -221,6 +225,7 @@ trayIcon->hide(); } #ifdef Q_OS_MAC + delete m_app_nap_inhibitor; delete appMenuBar; MacDockIconHandler::cleanup(); #endif @@ -1068,6 +1073,14 @@ void BitcoinGUI::setNumBlocks(int count, const QDateTime &blockDate, double nVerificationProgress, bool header) { +// Disabling macOS App Nap on initial sync, disk and reindex operations. +#ifdef Q_OS_MAC + (m_node.isInitialBlockDownload() || m_node.getReindex() || + m_node.getImporting()) + ? m_app_nap_inhibitor->disableAppNap() + : m_app_nap_inhibitor->enableAppNap(); +#endif + if (modalOverlay) { if (header) { modalOverlay->setKnownBestHeight(count, blockDate); diff --git a/src/qt/macos_appnap.h b/src/qt/macos_appnap.h new file mode 100644 --- /dev/null +++ b/src/qt/macos_appnap.h @@ -0,0 +1,23 @@ +// 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. + +#ifndef BITCOIN_QT_MACOS_APPNAP_H +#define BITCOIN_QT_MACOS_APPNAP_H + +#include + +class CAppNapInhibitor final { +public: + explicit CAppNapInhibitor(); + ~CAppNapInhibitor(); + + void disableAppNap(); + void enableAppNap(); + +private: + class CAppNapImpl; + std::unique_ptr impl; +}; + +#endif // BITCOIN_QT_MACOS_APPNAP_H diff --git a/src/qt/macos_appnap.mm b/src/qt/macos_appnap.mm new file mode 100644 --- /dev/null +++ b/src/qt/macos_appnap.mm @@ -0,0 +1,68 @@ +// 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 "macos_appnap.h" + +#include +#include +#include + +class CAppNapInhibitor::CAppNapImpl { +public: + ~CAppNapImpl() { + if (activityId) { + enableAppNap(); + } + } + + void disableAppNap() { + if (!activityId) { + @autoreleasepool { + const NSActivityOptions activityOptions = + NSActivityUserInitiatedAllowingIdleSystemSleep & + ~(NSActivitySuddenTerminationDisabled | + NSActivityAutomaticTerminationDisabled); + + id processInfo = [NSProcessInfo processInfo]; + if ([processInfo respondsToSelector:@selector + (beginActivityWithOptions:reason:)]) { + activityId = [processInfo + beginActivityWithOptions:activityOptions + reason:@"Temporarily disable App Nap " + @"for bitcoin-qt."]; + [activityId retain]; + } + } + } + } + + void enableAppNap() { + if (activityId) { + @autoreleasepool { + id processInfo = [NSProcessInfo processInfo]; + if ([processInfo respondsToSelector:@selector(endActivity:)]) { + [processInfo endActivity:activityId]; + } + + [activityId release]; + activityId = nil; + } + } + } + +private: + NSObject *activityId; +}; + +CAppNapInhibitor::CAppNapInhibitor() : impl(new CAppNapImpl()) {} + +CAppNapInhibitor::~CAppNapInhibitor() = default; + +void CAppNapInhibitor::disableAppNap() { + impl->disableAppNap(); +} + +void CAppNapInhibitor::enableAppNap() { + impl->enableAppNap(); +}