/**************************************************************************** ** ** Copyright (C) 2016 Ivan Vizir ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtWinExtras module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "qwintaskbarbutton.h" #include "qwintaskbarbutton_p.h" #include "qwintaskbarprogress.h" #include "qwinfunctions.h" #include "qwinfunctions_p.h" #include "qwineventfilter_p.h" #include "qwinevent.h" #include "winshobjidl_p.h" #include "windowsguidsdefs_p.h" #include #include #include #include #include QT_BEGIN_NAMESPACE /*! \class QWinTaskbarButton \inmodule QtWinExtras \brief The QWinTaskbarButton class represents the Windows taskbar button for a top-level window (Windows 7 and newer). \since 5.2 The QWinTaskbarButton class enables you to set overlay icons on a taskbar button, and provides access to its progress indicator. An overlay icon indicates change in the state of an application, whereas a progress indicator shows how time-consuming tasks are progressing. \image taskbar-button.png Taskbar Button The following example code illustrates how to use the QWinTaskbarButton and QWinTaskbarProgress classes to adjust the look of the taskbar button: \snippet code/taskbar.cpp taskbar_cpp \note QWidget::windowHandle() returns a valid instance of a QWindow only after the widget has been shown. It is therefore recommended to delay the initialization of the QWinTaskbarButton instances until QWidget::showEvent(). \note The class wraps API only available since Windows 7. Instantiating it on Windows XP or Windows Vista causes a runtime warning. \sa QWinTaskbarProgress */ static TBPFLAG nativeProgressState(QWinTaskbarProgress *progress) { if (!progress || !progress->isVisible()) return TBPF_NOPROGRESS; if (progress->isStopped()) return TBPF_ERROR; if (progress->isPaused()) return TBPF_PAUSED; if (progress->minimum() == 0 && progress->maximum() == 0) return TBPF_INDETERMINATE; return TBPF_NORMAL; } QWinTaskbarButtonPrivate::QWinTaskbarButtonPrivate() : progressBar(0), pTbList(0), window(0) { HRESULT hresult = CoCreateInstance(CLSID_TaskbarList, 0, CLSCTX_INPROC_SERVER, qIID_ITaskbarList4, reinterpret_cast(&pTbList)); if (FAILED(hresult)) { pTbList = 0; const QString err = QtWin::errorStringFromHresult(hresult); qWarning("QWinTaskbarButton: qIID_ITaskbarList4 was not created: %#010x, %s.", unsigned(hresult), qPrintable(err)); } else if (FAILED(pTbList->HrInit())) { pTbList->Release(); pTbList = 0; const QString err = QtWin::errorStringFromHresult(hresult); qWarning("QWinTaskbarButton: qIID_ITaskbarList4 was not initialized: %#010x, %s.", unsigned(hresult), qPrintable(err)); } } QWinTaskbarButtonPrivate::~QWinTaskbarButtonPrivate() { if (pTbList) pTbList->Release(); } HWND QWinTaskbarButtonPrivate::handle() { return reinterpret_cast(window->winId()); } int QWinTaskbarButtonPrivate::iconSize() const { return GetSystemMetrics(SM_CXSMICON); } void QWinTaskbarButtonPrivate::updateOverlayIcon() { if (!pTbList || !window) return; wchar_t *descrPtr = 0; HICON hicon = 0; if (!overlayAccessibleDescription.isEmpty()) descrPtr = qt_qstringToNullTerminated(overlayAccessibleDescription); if (!overlayIcon.isNull()) hicon = QtWin::toHICON(overlayIcon.pixmap(iconSize())); if (hicon) pTbList->SetOverlayIcon(handle(), hicon, descrPtr); else if (!hicon && !overlayIcon.isNull()) pTbList->SetOverlayIcon(handle(), static_cast(LoadImage(0, IDI_APPLICATION, IMAGE_ICON, SM_CXSMICON, SM_CYSMICON, LR_SHARED)), descrPtr); else pTbList->SetOverlayIcon(handle(), NULL, descrPtr); if (hicon) DestroyIcon(hicon); delete[] descrPtr; } void QWinTaskbarButtonPrivate::_q_updateProgress() { if (!pTbList || !window) return; if (progressBar) { const int min = progressBar->minimum(); const int max = progressBar->maximum(); const int range = max - min; if (range > 0) { const int value = qRound(double(100) * (double(progressBar->value() - min)) / double(range)); pTbList->SetProgressValue(handle(), ULONGLONG(value), 100); } } pTbList->SetProgressState(handle(), nativeProgressState(progressBar)); } /*! Constructs a QWinTaskbarButton with the specified \a parent. If \a parent is an instance of QWindow, it is automatically assigned as the taskbar button's \l window. */ QWinTaskbarButton::QWinTaskbarButton(QObject *parent) : QObject(parent), d_ptr(new QWinTaskbarButtonPrivate) { QWinEventFilter::setup(); setWindow(qobject_cast(parent)); } /*! Destroys the QWinTaskbarButton. */ QWinTaskbarButton::~QWinTaskbarButton() = default; /*! \property QWinTaskbarButton::window \brief the window whose taskbar button is manipulated */ void QWinTaskbarButton::setWindow(QWindow *window) { Q_D(QWinTaskbarButton); if (d->window) d->window->removeEventFilter(this); d->window = window; if (d->window) { d->window->installEventFilter(this); if (d->window->isVisible()) { d->_q_updateProgress(); d->updateOverlayIcon(); } } } QWindow *QWinTaskbarButton::window() const { Q_D(const QWinTaskbarButton); return d->window; } /*! \property QWinTaskbarButton::overlayIcon \brief the overlay icon of the taskbar button */ QIcon QWinTaskbarButton::overlayIcon() const { Q_D(const QWinTaskbarButton); return d->overlayIcon; } void QWinTaskbarButton::setOverlayIcon(const QIcon &icon) { Q_D(QWinTaskbarButton); d->overlayIcon = icon; d->updateOverlayIcon(); } void QWinTaskbarButton::clearOverlayIcon() { setOverlayAccessibleDescription(QString()); setOverlayIcon(QIcon()); } /*! \property QWinTaskbarButton::overlayAccessibleDescription \brief the description of the overlay for accessibility purposes \sa overlayIcon */ QString QWinTaskbarButton::overlayAccessibleDescription() const { Q_D(const QWinTaskbarButton); return d->overlayAccessibleDescription; } void QWinTaskbarButton::setOverlayAccessibleDescription(const QString &description) { Q_D(QWinTaskbarButton); d->overlayAccessibleDescription = description; d->updateOverlayIcon(); } /*! \property QWinTaskbarButton::progress \brief the progress indicator of the taskbar button \note The progress indicator is not \l{QWinTaskbarProgress::visible}{visible} by default. */ QWinTaskbarProgress *QWinTaskbarButton::progress() const { Q_D(const QWinTaskbarButton); if (!d->progressBar) { QWinTaskbarButton *that = const_cast(this); QWinTaskbarProgress *pbar = new QWinTaskbarProgress(that); connect(pbar, SIGNAL(destroyed()), this, SLOT(_q_updateProgress())); connect(pbar, SIGNAL(valueChanged(int)), this, SLOT(_q_updateProgress())); connect(pbar, SIGNAL(minimumChanged(int)), this, SLOT(_q_updateProgress())); connect(pbar, SIGNAL(maximumChanged(int)), this, SLOT(_q_updateProgress())); connect(pbar, SIGNAL(visibilityChanged(bool)), this, SLOT(_q_updateProgress())); connect(pbar, SIGNAL(pausedChanged(bool)), this, SLOT(_q_updateProgress())); connect(pbar, SIGNAL(stoppedChanged(bool)), this, SLOT(_q_updateProgress())); that->d_func()->progressBar = pbar; that->d_func()->_q_updateProgress(); } return d->progressBar; } /*! \internal Intercepts TaskbarButtonCreated messages. */ bool QWinTaskbarButton::eventFilter(QObject *object, QEvent *event) { Q_D(QWinTaskbarButton); if (object == d->window && event->type() == QWinEvent::TaskbarButtonCreated) { d->_q_updateProgress(); d->updateOverlayIcon(); } return false; } QT_END_NAMESPACE #include "moc_qwintaskbarbutton.cpp"