diff --git a/src/qt/CMakeLists.txt b/src/qt/CMakeLists.txt index eeba0fbd7c90a..087d10cdefc83 100644 --- a/src/qt/CMakeLists.txt +++ b/src/qt/CMakeLists.txt @@ -364,10 +364,14 @@ if(WITH_DBUS) target_link_libraries(bitcoinqt PRIVATE "Qt${WITH_QT_VERSION}::DBus") endif() if(WITH_TASKBAR_PROGRESS) + target_sources(bitcoinqt + PRIVATE + $<$:wintaskbarprogress.cpp> + $<$:wintaskbarprogress.h> + ) target_link_libraries(bitcoinqt PRIVATE - "Qt${WITH_QT_VERSION}::WinExtras" - $<$:dwmapi> + $<$:ole32> ) endif() diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index fb2922afc4b9b..898c1a25023a8 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -35,8 +35,7 @@ #include #endif #ifdef BITCOIN_QT_WIN_TASKBAR -#include -#include +#include #endif #include @@ -232,7 +231,8 @@ BitcoinGUI::BitcoinGUI(interfaces::Node& node, const PlatformStyle *_platformSty m_app_nap_inhibitor = new CAppNapInhibitor; #endif #ifdef BITCOIN_QT_WIN_TASKBAR - m_taskbar_button = new QWinTaskbarButton(this); + m_taskbar_progress = new WinTaskbarProgress(this); + m_taskbar_progress->setWindow(this); #endif GUIUtil::handleCloseWindowShortcut(this); @@ -1235,11 +1235,6 @@ void BitcoinGUI::setNumBlocks(int count, const QDateTime& blockDate, double nVer tooltip = tr("Processed %n block(s) of transaction history.", "", count); -#ifdef BITCOIN_QT_WIN_TASKBAR - m_taskbar_button->setWindow(windowHandle()); - QWinTaskbarProgress* taskbar_progress = m_taskbar_button->progress(); -#endif - // Set icon state: spinning if catching up, tick otherwise if (secs < MAX_BLOCK_TIME_GAP) { tooltip = tr("Up to date") + QString(".
") + tooltip; @@ -1256,7 +1251,7 @@ void BitcoinGUI::setNumBlocks(int count, const QDateTime& blockDate, double nVer progressBarLabel->setVisible(false); progressBar->setVisible(false); #ifdef BITCOIN_QT_WIN_TASKBAR - taskbar_progress->setVisible(false); + m_taskbar_progress->setVisible(false); #endif } else @@ -1273,8 +1268,8 @@ void BitcoinGUI::setNumBlocks(int count, const QDateTime& blockDate, double nVer progressBar->setValue(nVerificationProgress * 1000000000.0 + 0.5); progressBar->setVisible(true); #ifdef BITCOIN_QT_WIN_TASKBAR - taskbar_progress->setValue(qRound(nVerificationProgress * 100.0)); - taskbar_progress->setVisible(true); + m_taskbar_progress->setValue(qRound(nVerificationProgress * 100.0)); + m_taskbar_progress->setVisible(true); #endif tooltip = tr("Catching up…") + QString("
") + tooltip; diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h index f7ac119a019e9..c05f6e4b5d1aa 100644 --- a/src/qt/bitcoingui.h +++ b/src/qt/bitcoingui.h @@ -55,9 +55,10 @@ class QComboBox; class QDateTime; class QProgressBar; class QProgressDialog; -class QWinTaskbarButton; QT_END_NAMESPACE +class WinTaskbarProgress; + namespace GUIUtil { class ClickableLabel; class ClickableProgressBar; @@ -180,7 +181,7 @@ class BitcoinGUI : public QMainWindow RPCConsole* rpcConsole = nullptr; HelpMessageDialog* helpMessageDialog = nullptr; #ifdef BITCOIN_QT_WIN_TASKBAR - QWinTaskbarButton* m_taskbar_button = nullptr; + WinTaskbarProgress* m_taskbar_progress = nullptr; #endif ModalOverlay* modalOverlay = nullptr; MempoolStats* mempoolStats = nullptr; diff --git a/src/qt/wintaskbarprogress.cpp b/src/qt/wintaskbarprogress.cpp new file mode 100644 index 0000000000000..83ccd57af754e --- /dev/null +++ b/src/qt/wintaskbarprogress.cpp @@ -0,0 +1,108 @@ +// Copyright (c) 2025 The Bitcoin Knots developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include + +#include +#include + +#include +#include +#include + +WinTaskbarProgress::WinTaskbarProgress(QObject *parent) + : QObject(parent) +{ +} + +WinTaskbarProgress::~WinTaskbarProgress() +{ + releaseTaskbarButton(); +} + +void WinTaskbarProgress::setWindow(QWidget* widget) +{ + assert(!m_taskbar_button); + QWindow* window = widget ? widget->windowHandle() : nullptr; + if (m_window == window) { + return; + } + + m_window = window; + initTaskbarButton(); + updateProgress(); +} + +QWindow* WinTaskbarProgress::window() const +{ + return m_window; +} + +void WinTaskbarProgress::setValue(int value) +{ + if (m_value == value) { + return; + } + + m_value = value; + updateProgress(); +} + +void WinTaskbarProgress::setVisible(bool visible) +{ + if (m_visible == visible) { + return; + } + + m_visible = visible; + updateProgress(); +} + +void WinTaskbarProgress::updateProgress() +{ + if (!m_taskbar_button || !m_window) { + return; + } + + if (m_visible) { + // Set progress value + m_taskbar_button->SetProgressValue((HWND)m_window->winId(), m_value, 100); + // Set progress state to normal + m_taskbar_button->SetProgressState((HWND)m_window->winId(), TBPF_NORMAL); + } else { + // Hide progress bar + m_taskbar_button->SetProgressState((HWND)m_window->winId(), TBPF_NOPROGRESS); + } +} + +void WinTaskbarProgress::initTaskbarButton() +{ + if (m_taskbar_button || !m_window) { + return; + } + + HRESULT hr = CoCreateInstance(CLSID_TaskbarList, nullptr, CLSCTX_INPROC_SERVER, + IID_PPV_ARGS(&m_taskbar_button)); + + if (SUCCEEDED(hr)) { + hr = m_taskbar_button->HrInit(); + if (!SUCCEEDED(hr)) { + m_taskbar_button->Release(); + m_taskbar_button = nullptr; + } + } +} + +void WinTaskbarProgress::releaseTaskbarButton() +{ + if (!m_taskbar_button) { + return; + } + + if (m_window) { + m_taskbar_button->SetProgressState((HWND)m_window->winId(), TBPF_NOPROGRESS); + } + m_taskbar_button->Release(); + m_taskbar_button = nullptr; +} diff --git a/src/qt/wintaskbarprogress.h b/src/qt/wintaskbarprogress.h new file mode 100644 index 0000000000000..04e20f9797bf7 --- /dev/null +++ b/src/qt/wintaskbarprogress.h @@ -0,0 +1,62 @@ +// Copyright (c) 2025 The Bitcoin Knots developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_QT_WINTASKBARPROGRESS_H +#define BITCOIN_QT_WINTASKBARPROGRESS_H + +#include + +class QWidget; +class QWindow; +struct ITaskbarList3; + +/** + * Manages Windows taskbar button progress indicator. + * Provides a platform-independent wrapper around the native Windows API + * for taskbar progress updates. + */ +class WinTaskbarProgress : public QObject +{ + Q_OBJECT + +public: + explicit WinTaskbarProgress(QObject *parent = nullptr); + ~WinTaskbarProgress(); + + /** + * Set the window handle for taskbar progress updates + * @param[in] widget The QWidget to update taskbar progress for + */ + void setWindow(QWidget* widget); + + /** + * Get the current window handle + * @return The current QWindow pointer, or nullptr if not set + */ + QWindow* window() const; + + /** + * Set the progress value + * @param[in] value Progress value (0-100) + */ + void setValue(int value); + + /** + * Set progress visibility + * @param[in] visible True to show progress, false to hide + */ + void setVisible(bool visible); + +private: + QWindow* m_window = nullptr; + int m_value = 0; + bool m_visible = false; + ITaskbarList3* m_taskbar_button = nullptr; + + void updateProgress(); + void initTaskbarButton(); + void releaseTaskbarButton(); +}; + +#endif // BITCOIN_QT_WINTASKBARPROGRESS_H