Skip to content

Commit 8986737

Browse files
committed
qt: Port Windows taskbar progress to native Windows API
Replace QtWinExtras (removed in Qt6) with native Windows ITaskbarList3 COM API. This makes the Windows taskbar progress feature compatible with both Qt5 and Qt6. Changes: - Replace QtWinExtras with direct ITaskbarList3 COM interface - Create new WinTaskbarProgress class using Windows COM API - Use consistent Q_OS_WIN macro for Windows platform detection - Update CMakeLists.txt to link ole32 instead of Qt WinExtras The new implementation maintains full feature parity with the Qt5 version while working with both Qt5 and Qt6 without requiring QtWinExtras.
1 parent eeb9cc1 commit 8986737

File tree

5 files changed

+221
-15
lines changed

5 files changed

+221
-15
lines changed

src/qt/CMakeLists.txt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,8 @@ add_library(bitcoinqt STATIC EXCLUDE_FROM_ALL
257257
utilitydialog.h
258258
$<$<PLATFORM_ID:Windows>:winshutdownmonitor.cpp>
259259
$<$<PLATFORM_ID:Windows>:winshutdownmonitor.h>
260+
$<$<PLATFORM_ID:Windows>:wintaskbarprogress.cpp>
261+
$<$<PLATFORM_ID:Windows>:wintaskbarprogress.h>
260262
bitcoin.qrc
261263
${CMAKE_CURRENT_BINARY_DIR}/bitcoin_locale.qrc
262264
${CMAKE_CURRENT_BINARY_DIR}/bitcoin_rendered.qrc
@@ -366,8 +368,8 @@ endif()
366368
if(WITH_TASKBAR_PROGRESS)
367369
target_link_libraries(bitcoinqt
368370
PRIVATE
369-
"Qt${WITH_QT_VERSION}::WinExtras"
370-
$<$<PLATFORM_ID:Windows>:dwmapi>
371+
# Using native Windows API (ITaskbarList3), requires ole32 for COM
372+
$<$<PLATFORM_ID:Windows>:ole32>
371373
)
372374
endif()
373375

src/qt/bitcoingui.cpp

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,7 @@
3535
#include <qt/macdockiconhandler.h>
3636
#endif
3737
#ifdef BITCOIN_QT_WIN_TASKBAR
38-
#include <QWinTaskbarButton>
39-
#include <QWinTaskbarProgress>
38+
#include <qt/wintaskbarprogress.h>
4039
#endif
4140

4241
#include <chain.h>
@@ -232,7 +231,10 @@ BitcoinGUI::BitcoinGUI(interfaces::Node& node, const PlatformStyle *_platformSty
232231
m_app_nap_inhibitor = new CAppNapInhibitor;
233232
#endif
234233
#ifdef BITCOIN_QT_WIN_TASKBAR
235-
m_taskbar_button = new QWinTaskbarButton(this);
234+
m_taskbar_progress = new WinTaskbarProgress();
235+
if (windowHandle()) {
236+
m_taskbar_progress->setWindow(windowHandle());
237+
}
236238
#endif
237239

238240
GUIUtil::handleCloseWindowShortcut(this);
@@ -251,6 +253,9 @@ BitcoinGUI::~BitcoinGUI()
251253
delete m_app_nap_inhibitor;
252254
MacDockIconHandler::cleanup();
253255
#endif
256+
#ifdef BITCOIN_QT_WIN_TASKBAR
257+
delete m_taskbar_progress;
258+
#endif
254259

255260
delete NetWatch;
256261
delete rpcConsole;
@@ -1235,11 +1240,6 @@ void BitcoinGUI::setNumBlocks(int count, const QDateTime& blockDate, double nVer
12351240

12361241
tooltip = tr("Processed %n block(s) of transaction history.", "", count);
12371242

1238-
#ifdef BITCOIN_QT_WIN_TASKBAR
1239-
m_taskbar_button->setWindow(windowHandle());
1240-
QWinTaskbarProgress* taskbar_progress = m_taskbar_button->progress();
1241-
#endif
1242-
12431243
// Set icon state: spinning if catching up, tick otherwise
12441244
if (secs < MAX_BLOCK_TIME_GAP) {
12451245
tooltip = tr("Up to date") + QString(".<br>") + tooltip;
@@ -1256,7 +1256,7 @@ void BitcoinGUI::setNumBlocks(int count, const QDateTime& blockDate, double nVer
12561256
progressBarLabel->setVisible(false);
12571257
progressBar->setVisible(false);
12581258
#ifdef BITCOIN_QT_WIN_TASKBAR
1259-
taskbar_progress->setVisible(false);
1259+
m_taskbar_progress->setVisible(false);
12601260
#endif
12611261
}
12621262
else
@@ -1273,8 +1273,8 @@ void BitcoinGUI::setNumBlocks(int count, const QDateTime& blockDate, double nVer
12731273
progressBar->setValue(nVerificationProgress * 1000000000.0 + 0.5);
12741274
progressBar->setVisible(true);
12751275
#ifdef BITCOIN_QT_WIN_TASKBAR
1276-
taskbar_progress->setValue(qRound(nVerificationProgress * 100.0));
1277-
taskbar_progress->setVisible(true);
1276+
m_taskbar_progress->setValue(qRound(nVerificationProgress * 100.0));
1277+
m_taskbar_progress->setVisible(true);
12781278
#endif
12791279

12801280
tooltip = tr("Catching up…") + QString("<br>") + tooltip;
@@ -1445,6 +1445,13 @@ void BitcoinGUI::showEvent(QShowEvent *event)
14451445
showMempoolStatsAction->setEnabled(true);
14461446
aboutAction->setEnabled(true);
14471447
optionsAction->setEnabled(true);
1448+
1449+
#ifdef BITCOIN_QT_WIN_TASKBAR
1450+
// If window handle wasn't available during construction, set it now
1451+
if (m_taskbar_progress && !m_taskbar_progress->window() && windowHandle()) {
1452+
m_taskbar_progress->setWindow(windowHandle());
1453+
}
1454+
#endif
14481455
}
14491456

14501457
#ifdef ENABLE_WALLET

src/qt/bitcoingui.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,12 @@ class QComboBox;
5555
class QDateTime;
5656
class QProgressBar;
5757
class QProgressDialog;
58-
class QWinTaskbarButton;
5958
QT_END_NAMESPACE
6059

60+
#ifdef BITCOIN_QT_WIN_TASKBAR
61+
class WinTaskbarProgress;
62+
#endif
63+
6164
namespace GUIUtil {
6265
class ClickableLabel;
6366
class ClickableProgressBar;
@@ -180,7 +183,7 @@ class BitcoinGUI : public QMainWindow
180183
RPCConsole* rpcConsole = nullptr;
181184
HelpMessageDialog* helpMessageDialog = nullptr;
182185
#ifdef BITCOIN_QT_WIN_TASKBAR
183-
QWinTaskbarButton* m_taskbar_button = nullptr;
186+
WinTaskbarProgress* m_taskbar_progress = nullptr;
184187
#endif
185188
ModalOverlay* modalOverlay = nullptr;
186189
MempoolStats* mempoolStats = nullptr;

src/qt/wintaskbarprogress.cpp

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
// Copyright (c) 2025 The Bitcoin Knots developers
2+
// Distributed under the MIT software license, see the accompanying
3+
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4+
5+
#include <qt/wintaskbarprogress.h>
6+
7+
#if defined(Q_OS_WIN)
8+
9+
#include <QWindow>
10+
11+
#include <windows.h>
12+
#include <shobjidl.h>
13+
14+
WinTaskbarProgress::WinTaskbarProgress()
15+
{
16+
}
17+
18+
WinTaskbarProgress::~WinTaskbarProgress()
19+
{
20+
releaseTaskbar();
21+
}
22+
23+
void WinTaskbarProgress::setWindow(QWindow* window)
24+
{
25+
m_window = window;
26+
}
27+
28+
void WinTaskbarProgress::initializeTaskbar()
29+
{
30+
if (m_initialized || !m_window) {
31+
return;
32+
}
33+
34+
HWND winId = reinterpret_cast<HWND>(m_window->winId());
35+
if (!winId) {
36+
return;
37+
}
38+
39+
HRESULT hr = CoCreateInstance(
40+
CLSID_TaskbarList,
41+
nullptr,
42+
CLSCTX_INPROC_SERVER,
43+
IID_ITaskbarList3,
44+
reinterpret_cast<void**>(&m_taskbarList)
45+
);
46+
47+
if (SUCCEEDED(hr) && m_taskbarList) {
48+
hr = m_taskbarList->HrInit();
49+
if (SUCCEEDED(hr)) {
50+
m_initialized = true;
51+
} else {
52+
m_taskbarList->Release();
53+
m_taskbarList = nullptr;
54+
}
55+
}
56+
}
57+
58+
void WinTaskbarProgress::releaseTaskbar()
59+
{
60+
if (m_taskbarList) {
61+
// Clear progress state before releasing
62+
if (m_window) {
63+
HWND winId = reinterpret_cast<HWND>(m_window->winId());
64+
if (winId) {
65+
m_taskbarList->SetProgressState(winId, TBPF_NOPROGRESS);
66+
}
67+
}
68+
m_taskbarList->Release();
69+
m_taskbarList = nullptr;
70+
}
71+
m_initialized = false;
72+
m_visible = false;
73+
}
74+
75+
void WinTaskbarProgress::setValue(int value)
76+
{
77+
// Lazy initialization on first use
78+
if (!m_initialized) {
79+
initializeTaskbar();
80+
}
81+
82+
if (!m_initialized || !m_taskbarList || !m_window) {
83+
return;
84+
}
85+
86+
HWND winId = reinterpret_cast<HWND>(m_window->winId());
87+
if (!winId) {
88+
return;
89+
}
90+
91+
// Clamp value to 0-100
92+
if (value < 0) value = 0;
93+
if (value > 100) value = 100;
94+
95+
// Use indeterminate mode for very low progress (< 1%) to show activity
96+
// Otherwise progress of 0 is invisible on the taskbar
97+
if (value < 1) {
98+
m_taskbarList->SetProgressState(winId, TBPF_INDETERMINATE);
99+
m_visible = true;
100+
return;
101+
}
102+
103+
// Switch to normal mode if not already visible
104+
if (!m_visible) {
105+
m_taskbarList->SetProgressState(winId, TBPF_NORMAL);
106+
m_visible = true;
107+
}
108+
109+
// Set progress value (current, maximum)
110+
m_taskbarList->SetProgressValue(winId, value, 100);
111+
}
112+
113+
void WinTaskbarProgress::setVisible(bool visible)
114+
{
115+
if (!m_initialized || !m_taskbarList || !m_window) {
116+
return;
117+
}
118+
119+
HWND winId = reinterpret_cast<HWND>(m_window->winId());
120+
if (!winId) {
121+
return;
122+
}
123+
124+
if (visible && !m_visible) {
125+
// Show normal progress
126+
m_taskbarList->SetProgressState(winId, TBPF_NORMAL);
127+
m_visible = true;
128+
} else if (!visible && m_visible) {
129+
// Hide progress
130+
m_taskbarList->SetProgressState(winId, TBPF_NOPROGRESS);
131+
m_visible = false;
132+
}
133+
}
134+
135+
void WinTaskbarProgress::reset()
136+
{
137+
setVisible(false);
138+
}
139+
140+
#endif // Q_OS_WIN

src/qt/wintaskbarprogress.h

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// Copyright (c) 2025 The Bitcoin Knots developers
2+
// Distributed under the MIT software license, see the accompanying
3+
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4+
5+
#ifndef BITCOIN_QT_WINTASKBARPROGRESS_H
6+
#define BITCOIN_QT_WINTASKBARPROGRESS_H
7+
8+
#ifdef Q_OS_WIN
9+
#include <QWindow>
10+
11+
#include <windows.h>
12+
13+
// Forward declarations for COM interfaces
14+
struct ITaskbarList3;
15+
16+
/**
17+
* Native Windows taskbar progress indicator
18+
* Uses ITaskbarList3 COM interface for Windows 7+ compatibility
19+
* Works with both Qt5 and Qt6
20+
*/
21+
class WinTaskbarProgress
22+
{
23+
public:
24+
WinTaskbarProgress();
25+
~WinTaskbarProgress();
26+
27+
/** Set the window handle to attach progress to */
28+
void setWindow(QWindow* window);
29+
30+
/** Get the window handle */
31+
QWindow* window() const { return m_window; }
32+
33+
/** Set progress value (0-100) */
34+
void setValue(int value);
35+
36+
/** Show or hide the progress indicator */
37+
void setVisible(bool visible);
38+
39+
/** Reset progress state */
40+
void reset();
41+
42+
private:
43+
QWindow* m_window{nullptr};
44+
ITaskbarList3* m_taskbarList{nullptr};
45+
bool m_initialized{false};
46+
bool m_visible{false};
47+
48+
void initializeTaskbar();
49+
void releaseTaskbar();
50+
};
51+
52+
#endif // Q_OS_WIN
53+
54+
#endif // BITCOIN_QT_WINTASKBARPROGRESS_H

0 commit comments

Comments
 (0)