diff options
Diffstat (limited to 'src/winextras/qwinthumbnailtoolbar.cpp')
-rw-r--r-- | src/winextras/qwinthumbnailtoolbar.cpp | 629 |
1 files changed, 0 insertions, 629 deletions
diff --git a/src/winextras/qwinthumbnailtoolbar.cpp b/src/winextras/qwinthumbnailtoolbar.cpp deleted file mode 100644 index fc8d76e..0000000 --- a/src/winextras/qwinthumbnailtoolbar.cpp +++ /dev/null @@ -1,629 +0,0 @@ -/**************************************************************************** - ** - ** Copyright (C) 2016 Ivan Vizir <define-true-false@yandex.com> - ** 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$ - ** - ****************************************************************************/ - -#if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0601 -# undef _WIN32_WINNT -#endif -#if !defined(_WIN32_WINNT) -# define _WIN32_WINNT 0x0601 // Enable functions for MinGW -#endif - -#include "qwinthumbnailtoolbar.h" -#include "qwinthumbnailtoolbar_p.h" -#include "qwinthumbnailtoolbutton.h" -#include "qwinthumbnailtoolbutton_p.h" -#include "windowsguidsdefs_p.h" -#include "qwinfunctions.h" - -#include <QtGui/qwindow.h> -#include <QtCore/qcoreapplication.h> -#include <QtCore/qtimer.h> -#include <QtCore/qdebug.h> - -#include "qwinevent.h" -#include "qwinfunctions_p.h" -#include "qwineventfilter_p.h" - -#ifndef THBN_CLICKED -# define THBN_CLICKED 0x1800 -#endif - -#ifndef WM_DWMSENDICONICLIVEPREVIEWBITMAP -# define WM_DWMSENDICONICLIVEPREVIEWBITMAP 0x0326 -#endif - -#ifndef WM_DWMSENDICONICTHUMBNAIL -# define WM_DWMSENDICONICTHUMBNAIL 0x0323 -#endif - -QT_BEGIN_NAMESPACE - -enum { dWM_SIT_DISPLAYFRAME = 1 , dWMWA_FORCE_ICONIC_REPRESENTATION = 7, dWMWA_HAS_ICONIC_BITMAP = 10 }; - -static const int windowsLimitedThumbbarSize = 7; - -/*! - \class QWinThumbnailToolBar - \inmodule QtWinExtras - \since 5.2 - \brief The QWinThumbnailToolBar class allows manipulating the thumbnail toolbar of a window. - - Applications can embed a toolbar in the thumbnail of a window, which is - shown when hovering over its taskbar icon. A thumbnail toolbar may provide - quick access to the commands of a window without requiring the user to restore - or activate the window. - - \image thumbbar.png Media player thumbnail toolbar - - The following example code illustrates how to use the functions in the - QWinThumbnailToolBar and QWinThumbnailToolButton class to implement a - thumbnail toolbar: - - \snippet code/thumbbar.cpp thumbbar_cpp - - \sa QWinThumbnailToolButton - */ - -/*! - Constructs a QWinThumbnailToolBar with the specified \a parent. - - If \a parent is an instance of QWindow, it is automatically - assigned as the thumbnail toolbar's \l window. - */ -QWinThumbnailToolBar::QWinThumbnailToolBar(QObject *parent) : - QObject(parent), d_ptr(new QWinThumbnailToolBarPrivate) -{ - Q_D(QWinThumbnailToolBar); - d->q_ptr = this; - QWinEventFilter::setup(); - setWindow(qobject_cast<QWindow *>(parent)); -} - -/*! - Destroys and clears the QWinThumbnailToolBar. - */ -QWinThumbnailToolBar::~QWinThumbnailToolBar() = default; - -/*! - \property QWinThumbnailToolBar::window - \brief the window whose thumbnail toolbar is manipulated - */ -void QWinThumbnailToolBar::setWindow(QWindow *window) -{ - Q_D(QWinThumbnailToolBar); - if (d->window != window) { - if (d->window) { - d->window->removeEventFilter(d); - if (d->window->handle()) { - d->clearToolbar(); - setIconicPixmapNotificationsEnabled(false); - } - } - d->window = window; - if (d->window) { - d->window->installEventFilter(d); - if (d->window->isVisible()) { - d->initToolbar(); - d->_q_scheduleUpdate(); - } - } - } -} - -QWindow *QWinThumbnailToolBar::window() const -{ - Q_D(const QWinThumbnailToolBar); - return d->window; -} - -/*! - Adds a \a button to the thumbnail toolbar. - - \note The number of buttons is limited to \c 7. - */ -void QWinThumbnailToolBar::addButton(QWinThumbnailToolButton *button) -{ - Q_D(QWinThumbnailToolBar); - if (d->buttonList.size() >= windowsLimitedThumbbarSize) { - qWarning() << "Cannot add " << button << " maximum number of buttons (" - << windowsLimitedThumbbarSize << ") reached."; - return; - } - if (button && button->d_func()->toolbar != this) { - if (button->d_func()->toolbar) { - button->d_func()->toolbar->removeButton(button); - } - button->d_func()->toolbar = this; - connect(button, &QWinThumbnailToolButton::changed, - d, &QWinThumbnailToolBarPrivate::_q_scheduleUpdate); - d->buttonList.append(button); - d->_q_scheduleUpdate(); - } -} - -/*! - Removes the \a button from the thumbnail toolbar. - */ -void QWinThumbnailToolBar::removeButton(QWinThumbnailToolButton *button) -{ - Q_D(QWinThumbnailToolBar); - if (button && d->buttonList.contains(button)) { - button->d_func()->toolbar = nullptr; - disconnect(button, &QWinThumbnailToolButton::changed, - d, &QWinThumbnailToolBarPrivate::_q_scheduleUpdate); - - d->buttonList.removeAll(button); - d->_q_scheduleUpdate(); - } -} - -/*! - Sets the list of \a buttons in the thumbnail toolbar. - - \note Any existing buttons are replaced. - */ -void QWinThumbnailToolBar::setButtons(const QList<QWinThumbnailToolButton *> &buttons) -{ - Q_D(QWinThumbnailToolBar); - d->buttonList.clear(); - for (QWinThumbnailToolButton *button : buttons) - addButton(button); - d->_q_updateToolbar(); -} - -/*! - Returns the list of buttons in the thumbnail toolbar. - */ -QList<QWinThumbnailToolButton *> QWinThumbnailToolBar::buttons() const -{ - Q_D(const QWinThumbnailToolBar); - return d->buttonList; -} - -/*! - \property QWinThumbnailToolBar::count - \brief the number of buttons in the thumbnail toolbar - - \note The number of buttons is limited to \c 7. - */ -int QWinThumbnailToolBar::count() const -{ - Q_D(const QWinThumbnailToolBar); - return d->buttonList.size(); -} - -void QWinThumbnailToolBarPrivate::updateIconicPixmapsEnabled(bool invalidate) -{ - Q_Q(QWinThumbnailToolBar); - const HWND hwnd = handle(); - if (!hwnd) { - qWarning() << Q_FUNC_INFO << "invoked with hwnd=0"; - return; - } - const bool enabled = iconicThumbnail || iconicLivePreview; - q->setIconicPixmapNotificationsEnabled(enabled); - if (enabled && invalidate) { - const HRESULT hr = DwmInvalidateIconicBitmaps(hwnd); - if (FAILED(hr)) - qWarning() << QWinThumbnailToolBarPrivate::msgComFailed("DwmInvalidateIconicBitmaps", hr); - } -} - -/* - QWinThumbnailToolBarPrivate::IconicPixmapCache caches a HBITMAP of for one of - the iconic thumbnail or live preview pixmaps. When the messages - WM_DWMSENDICONICLIVEPREVIEWBITMAP or WM_DWMSENDICONICTHUMBNAIL are received - (after setting the DWM window attributes accordingly), the bitmap matching the - maximum size is constructed on demand. - */ - -void QWinThumbnailToolBarPrivate::IconicPixmapCache::deleteBitmap() -{ - if (m_bitmap) { - DeleteObject(m_bitmap); - m_size = QSize(); - m_bitmap = nullptr; - } -} - -bool QWinThumbnailToolBarPrivate::IconicPixmapCache::setPixmap(const QPixmap &pixmap) -{ - if (pixmap.cacheKey() == m_pixmap.cacheKey()) - return false; - deleteBitmap(); - m_pixmap = pixmap; - return true; -} - -HBITMAP QWinThumbnailToolBarPrivate::IconicPixmapCache::bitmap(const QSize &maxSize) -{ - if (m_pixmap.isNull()) - return nullptr; - if (m_bitmap && m_size.width() <= maxSize.width() && m_size.height() <= maxSize.height()) - return m_bitmap; - deleteBitmap(); - QPixmap pixmap = m_pixmap; - if (pixmap.width() >= maxSize.width() || pixmap.height() >= maxSize.width()) - pixmap = pixmap.scaled(maxSize, Qt::KeepAspectRatio, Qt::SmoothTransformation); - if (const HBITMAP bitmap = QtWin::toHBITMAP(pixmap, QtWin::HBitmapAlpha)) { - m_size = pixmap.size(); - m_bitmap = bitmap; - } - return m_bitmap; -} - -/*! - \fn QWinThumbnailToolBar::iconicThumbnailPixmapRequested() - - This signal is emitted when the operating system requests a new iconic thumbnail pixmap, - typically when the thumbnail is shown. - - \since 5.4 - \sa iconicThumbnailPixmap -*/ - -/*! - \fn QWinThumbnailToolBar::iconicLivePreviewPixmapRequested() - - This signal is emitted when the operating system requests a new iconic live preview pixmap, - typically when the user ALT-tabs to the application. - - \since 5.4 - \sa iconicLivePreviewPixmap -*/ - -/*! - \property QWinThumbnailToolBar::iconicPixmapNotificationsEnabled - \brief whether signals iconicThumbnailPixmapRequested() and iconicLivePreviewPixmapRequested() - will be emitted - - \since 5.4 - \sa QWinThumbnailToolBar::iconicThumbnailPixmap, QWinThumbnailToolBar::iconicLivePreviewPixmap - */ - -bool QWinThumbnailToolBar::iconicPixmapNotificationsEnabled() const -{ - Q_D(const QWinThumbnailToolBar); - const HWND hwnd = d->handle(); - if (!hwnd) - return false; - return QtDwmApiDll::booleanWindowAttribute(hwnd, dWMWA_FORCE_ICONIC_REPRESENTATION); -} - -void QWinThumbnailToolBar::setIconicPixmapNotificationsEnabled(bool enabled) -{ - Q_D(const QWinThumbnailToolBar); - const HWND hwnd = d->handle(); - if (!hwnd) { - qWarning() << Q_FUNC_INFO << "invoked with hwnd=0"; - return; - } - if (iconicPixmapNotificationsEnabled() == enabled) - return; - QtDwmApiDll::setBooleanWindowAttribute(hwnd, dWMWA_FORCE_ICONIC_REPRESENTATION, enabled); - QtDwmApiDll::setBooleanWindowAttribute(hwnd, dWMWA_HAS_ICONIC_BITMAP, enabled); -} - -/*! - \property QWinThumbnailToolBar::iconicThumbnailPixmap - \brief the pixmap for use as a thumbnail representation - - \since 5.4 - \sa QWinThumbnailToolBar::iconicPixmapNotificationsEnabled - */ - -void QWinThumbnailToolBar::setIconicThumbnailPixmap(const QPixmap &pixmap) -{ - Q_D(QWinThumbnailToolBar); - const bool changed = d->iconicThumbnail.setPixmap(pixmap); - if (d->hasHandle()) // Potentially 0 when invoked from QML loading, see _q_updateToolbar() - d->updateIconicPixmapsEnabled(changed && !d->withinIconicThumbnailRequest); -} - -QPixmap QWinThumbnailToolBar::iconicThumbnailPixmap() const -{ - Q_D(const QWinThumbnailToolBar); - return d->iconicThumbnail.pixmap(); -} - -/*! - \property QWinThumbnailToolBar::iconicLivePreviewPixmap - \brief the pixmap for use as a live (peek) preview when tabbing into the application - - \since 5.4 - */ - -void QWinThumbnailToolBar::setIconicLivePreviewPixmap(const QPixmap &pixmap) -{ - Q_D(QWinThumbnailToolBar); - const bool changed = d->iconicLivePreview.setPixmap(pixmap); - if (d->hasHandle()) // Potentially 0 when invoked from QML loading, see _q_updateToolbar() - d->updateIconicPixmapsEnabled(changed && !d->withinIconicLivePreviewRequest); -} - -QPixmap QWinThumbnailToolBar::iconicLivePreviewPixmap() const -{ - Q_D(const QWinThumbnailToolBar); - return d->iconicLivePreview.pixmap(); -} - -inline void QWinThumbnailToolBarPrivate::updateIconicThumbnail(const MSG *message) -{ - if (!iconicThumbnail) - return; - const QSize maxSize(HIWORD(message->lParam), LOWORD(message->lParam)); - if (const HBITMAP bitmap = iconicThumbnail.bitmap(maxSize)) { - const HRESULT hr = DwmSetIconicThumbnail(message->hwnd, bitmap, dWM_SIT_DISPLAYFRAME); - if (FAILED(hr)) - qWarning() << QWinThumbnailToolBarPrivate::msgComFailed("DwmSetIconicThumbnail", hr); - } -} - -inline void QWinThumbnailToolBarPrivate::updateIconicLivePreview(const MSG *message) -{ - if (!iconicLivePreview) - return; - RECT rect; - GetClientRect(message->hwnd, &rect); - const QSize maxSize(rect.right, rect.bottom); - POINT offset = {0, 0}; - if (const HBITMAP bitmap = iconicLivePreview.bitmap(maxSize)) { - const HRESULT hr = DwmSetIconicLivePreviewBitmap(message->hwnd, bitmap, &offset, dWM_SIT_DISPLAYFRAME); - if (FAILED(hr)) - qWarning() << QWinThumbnailToolBarPrivate::msgComFailed("DwmSetIconicLivePreviewBitmap", hr); - } -} - -/*! - Removes all buttons from the thumbnail toolbar. - */ -void QWinThumbnailToolBar::clear() -{ - setButtons(QList<QWinThumbnailToolButton *>()); -} - -static inline ITaskbarList4 *createTaskbarList() -{ - ITaskbarList4 *result = nullptr; - HRESULT hresult = CoCreateInstance(CLSID_TaskbarList, nullptr, CLSCTX_INPROC_SERVER, qIID_ITaskbarList4, reinterpret_cast<void **>(&result)); - if (FAILED(hresult)) { - const QString err = QtWin::errorStringFromHresult(hresult); - qWarning("QWinThumbnailToolBar: qIID_ITaskbarList4 was not created: %#010x, %s.", - unsigned(hresult), qPrintable(err)); - return nullptr; - } - hresult = result->HrInit(); - if (FAILED(hresult)) { - result->Release(); - const QString err = QtWin::errorStringFromHresult(hresult); - qWarning("QWinThumbnailToolBar: qIID_ITaskbarList4 was not initialized: %#010x, %s.", - unsigned(hresult), qPrintable(err)); - return nullptr; - } - return result; -} - -QWinThumbnailToolBarPrivate::QWinThumbnailToolBarPrivate() : - QObject(nullptr), pTbList(createTaskbarList()) -{ - buttonList.reserve(windowsLimitedThumbbarSize); - QCoreApplication::instance()->installNativeEventFilter(this); -} - -QWinThumbnailToolBarPrivate::~QWinThumbnailToolBarPrivate() -{ - if (pTbList) - pTbList->Release(); - QCoreApplication::instance()->removeNativeEventFilter(this); -} - -inline bool QWinThumbnailToolBarPrivate::hasHandle() const -{ - return window && window->handle(); -} - -inline HWND QWinThumbnailToolBarPrivate::handle() const -{ - return hasHandle() ? reinterpret_cast<HWND>(window->winId()) : nullptr; -} - -void QWinThumbnailToolBarPrivate::initToolbar() -{ - if (!pTbList || !window) - return; - THUMBBUTTON buttons[windowsLimitedThumbbarSize]; - initButtons(buttons); - HRESULT hresult = pTbList->ThumbBarAddButtons(handle(), windowsLimitedThumbbarSize, buttons); - if (FAILED(hresult)) - qWarning() << msgComFailed("ThumbBarAddButtons", hresult); -} - -void QWinThumbnailToolBarPrivate::clearToolbar() -{ - if (!pTbList || !window) - return; - THUMBBUTTON buttons[windowsLimitedThumbbarSize]; - initButtons(buttons); - HRESULT hresult = pTbList->ThumbBarUpdateButtons(handle(), windowsLimitedThumbbarSize, buttons); - if (FAILED(hresult)) - qWarning() << msgComFailed("ThumbBarUpdateButtons", hresult); -} - -void QWinThumbnailToolBarPrivate::_q_updateToolbar() -{ - updateScheduled = false; - if (!pTbList || !window) - return; - THUMBBUTTON buttons[windowsLimitedThumbbarSize]; - QList<HICON> createdIcons; - initButtons(buttons); - const int thumbbarSize = qMin(buttonList.size(), windowsLimitedThumbbarSize); - // filling from the right fixes some strange bug which makes last button bg look like first btn bg - for (int i = (windowsLimitedThumbbarSize - thumbbarSize); i < windowsLimitedThumbbarSize; i++) { - QWinThumbnailToolButton *button = buttonList.at(i - (windowsLimitedThumbbarSize - thumbbarSize)); - buttons[i].dwFlags = static_cast<THUMBBUTTONFLAGS>(makeNativeButtonFlags(button)); - buttons[i].dwMask = static_cast<THUMBBUTTONMASK>(makeButtonMask(button)); - if (!button->icon().isNull()) {; - buttons[i].hIcon = QtWin::toHICON(button->icon().pixmap(GetSystemMetrics(SM_CXSMICON))); - if (!buttons[i].hIcon) - buttons[i].hIcon = static_cast<HICON>(LoadImage(nullptr, IDI_APPLICATION, IMAGE_ICON, SM_CXSMICON, SM_CYSMICON, LR_SHARED)); - else - createdIcons << buttons[i].hIcon; - } - if (!button->toolTip().isEmpty()) { - buttons[i].szTip[button->toolTip().left(sizeof(buttons[i].szTip)/sizeof(buttons[i].szTip[0]) - 1).toWCharArray(buttons[i].szTip)] = 0; - } - } - HRESULT hresult = pTbList->ThumbBarUpdateButtons(handle(), windowsLimitedThumbbarSize, buttons); - if (FAILED(hresult)) - qWarning() << msgComFailed("ThumbBarUpdateButtons", hresult); - updateIconicPixmapsEnabled(false); - for (auto & button : buttons) { - if (button.hIcon) { - if (createdIcons.contains(button.hIcon)) - DestroyIcon(button.hIcon); - else - DeleteObject(button.hIcon); - } - } -} - -void QWinThumbnailToolBarPrivate::_q_scheduleUpdate() -{ - if (updateScheduled) - return; - updateScheduled = true; - QTimer::singleShot(0, this, &QWinThumbnailToolBarPrivate::_q_updateToolbar); -} - -bool QWinThumbnailToolBarPrivate::eventFilter(QObject *object, QEvent *event) -{ - if (object == window && event->type() == QWinEvent::TaskbarButtonCreated) { - initToolbar(); - _q_scheduleUpdate(); - } - return QObject::eventFilter(object, event); -} - -#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) -bool QWinThumbnailToolBarPrivate::nativeEventFilter(const QByteArray &, void *message, qintptr *result) -#else -bool QWinThumbnailToolBarPrivate::nativeEventFilter(const QByteArray &, void *message, long *result) -#endif -{ - const MSG *msg = static_cast<const MSG *>(message); - if (handle() != msg->hwnd) - return false; - switch (msg->message) { - case WM_COMMAND: - if (HIWORD(msg->wParam) == THBN_CLICKED) { - const int buttonId = LOWORD(msg->wParam) - (windowsLimitedThumbbarSize - qMin(windowsLimitedThumbbarSize, buttonList.size())); - buttonList.at(buttonId)->click(); - if (result) - *result = 0; - return true; - } - break; - case WM_DWMSENDICONICTHUMBNAIL: - withinIconicThumbnailRequest = true; - emit q_func()->iconicThumbnailPixmapRequested(); - withinIconicThumbnailRequest = false; - updateIconicThumbnail(msg); - return true; - case WM_DWMSENDICONICLIVEPREVIEWBITMAP: - withinIconicLivePreviewRequest = true; - emit q_func()->iconicLivePreviewPixmapRequested(); - withinIconicLivePreviewRequest = false; - updateIconicLivePreview(msg); - return true; - } - return false; -} - -void QWinThumbnailToolBarPrivate::initButtons(THUMBBUTTON *buttons) -{ - for (int i = 0; i < windowsLimitedThumbbarSize; i++) { - memset(&buttons[i], 0, sizeof buttons[i]); - buttons[i].iId = UINT(i); - buttons[i].dwFlags = THBF_HIDDEN; - buttons[i].dwMask = THB_FLAGS; - } -} - -int QWinThumbnailToolBarPrivate::makeNativeButtonFlags(const QWinThumbnailToolButton *button) -{ - int nativeFlags = 0; - if (button->isEnabled()) - nativeFlags |= THBF_ENABLED; - else - nativeFlags |= THBF_DISABLED; - if (button->dismissOnClick()) - nativeFlags |= THBF_DISMISSONCLICK; - if (button->isFlat()) - nativeFlags |= THBF_NOBACKGROUND; - if (!button->isVisible()) - nativeFlags |= THBF_HIDDEN; - if (!button->isInteractive()) - nativeFlags |= THBF_NONINTERACTIVE; - return nativeFlags; -} - -int QWinThumbnailToolBarPrivate::makeButtonMask(const QWinThumbnailToolButton *button) -{ - int mask = 0; - mask |= THB_FLAGS; - if (!button->icon().isNull()) - mask |= THB_ICON; - if (!button->toolTip().isEmpty()) - mask |= THB_TOOLTIP; - return mask; -} - -QString QWinThumbnailToolBarPrivate::msgComFailed(const char *function, HRESULT hresult) -{ - return QString::fromLatin1("QWinThumbnailToolBar: %1() failed: #%2: %3") - .arg(QLatin1String(function)) - .arg(unsigned(hresult), 10, 16, QLatin1Char('0')) - .arg(QtWin::errorStringFromHresult(hresult)); -} - -QT_END_NAMESPACE - -#include "moc_qwinthumbnailtoolbar.cpp" |