wintaskbarprogress.cpp raw

   1  // Copyright (c) 2025 The Limenka 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  #include <QWidget>
   8  #include <QWindow>
   9  
  10  #include <windows.h>
  11  #include <shobjidl.h>
  12  
  13  WinTaskbarProgress::WinTaskbarProgress(QObject *parent)
  14      : QObject(parent),
  15        m_taskbar_button_created_msg(RegisterWindowMessageW(L"TaskbarButtonCreated"))
  16  {
  17  }
  18  
  19  WinTaskbarProgress::~WinTaskbarProgress()
  20  {
  21      releaseTaskbarButton();
  22  }
  23  
  24  void WinTaskbarProgress::setWindow(QWidget* widget)
  25  {
  26      QWindow* window = widget ? widget->windowHandle() : nullptr;
  27      if (!window) {
  28          return;
  29      }
  30      if (m_window == window) {
  31          return;
  32      }
  33  
  34      m_window = window;
  35      initTaskbarButton();
  36      updateProgress();
  37  }
  38  
  39  void WinTaskbarProgress::setValue(int value)
  40  {
  41      if (m_value == value) {
  42          return;
  43      }
  44  
  45      m_value = value;
  46      updateProgress();
  47  }
  48  
  49  void WinTaskbarProgress::setVisible(bool visible)
  50  {
  51      if (m_visible == visible) {
  52          return;
  53      }
  54  
  55      m_visible = visible;
  56      updateProgress();
  57  }
  58  
  59  void WinTaskbarProgress::updateProgress()
  60  {
  61      if (!m_taskbar_button || !m_window) {
  62          return;
  63      }
  64  
  65      HWND hwnd = reinterpret_cast<HWND>(m_window->winId());
  66      if (m_visible) {
  67          m_taskbar_button->SetProgressValue(hwnd, m_value, 100);
  68          m_taskbar_button->SetProgressState(hwnd, TBPF_NORMAL);
  69      } else {
  70          m_taskbar_button->SetProgressState(hwnd, TBPF_NOPROGRESS);
  71      }
  72  }
  73  
  74  void WinTaskbarProgress::initTaskbarButton()
  75  {
  76      if (m_taskbar_button || !m_window || !m_taskbar_ready) {
  77          return;
  78      }
  79  
  80      HRESULT hr = CoCreateInstance(CLSID_TaskbarList, nullptr, CLSCTX_INPROC_SERVER,
  81                                    IID_PPV_ARGS(&m_taskbar_button));
  82  
  83      if (SUCCEEDED(hr)) {
  84          hr = m_taskbar_button->HrInit();
  85          if (FAILED(hr)) {
  86              m_taskbar_button->Release();
  87              m_taskbar_button = nullptr;
  88          }
  89      }
  90  }
  91  
  92  void WinTaskbarProgress::releaseTaskbarButton()
  93  {
  94      if (m_taskbar_button) {
  95          m_taskbar_button->Release();
  96          m_taskbar_button = nullptr;
  97      }
  98  }
  99  
 100  #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
 101  bool WinTaskbarProgress::nativeEventFilter(const QByteArray &eventType, void *pMessage, qintptr *pnResult)
 102  #else
 103  bool WinTaskbarProgress::nativeEventFilter(const QByteArray &eventType, void *pMessage, long *pnResult)
 104  #endif
 105  {
 106      Q_UNUSED(pnResult);
 107  
 108      if (eventType != "windows_generic_MSG" && eventType != "windows_dispatcher_MSG") {
 109          return false;
 110      }
 111  
 112      MSG *msg = static_cast<MSG *>(pMessage);
 113  
 114      if (m_taskbar_button_created_msg != 0 && msg->message == m_taskbar_button_created_msg) {
 115          m_taskbar_ready = true;
 116          if (m_window) {
 117              initTaskbarButton();
 118              updateProgress();
 119          }
 120      }
 121  
 122      return false;
 123  }
 124