| /**************************************************************************** |
| ** |
| ** 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" |