diff options
author | Friedemann Kleint <Friedemann.Kleint@digia.com> | 2014-05-27 11:49:54 +0200 |
---|---|---|
committer | Friedemann Kleint <Friedemann.Kleint@digia.com> | 2014-07-07 11:10:28 +0200 |
commit | cef1f2fab06ed9d01d525681f5a11db67bb8f262 (patch) | |
tree | eca3a46df630bdb770ee708a908fc4b38816c9af /src | |
parent | 7bb27be8c5ce9a67a413022d627d9580cddbe64e (diff) |
Implement iconic live previews/iconic thumbnail icons.
[ChangeLog][QWinThumbnailToolBar] Added pixmap properties
and change notifications for thumbnail icons and live
preview.
Task-number: QTBUG-36730
Change-Id: I31ad0ff347235bc7933c1c14dece359ec0c36b39
Reviewed-by: Oliver Wolff <oliver.wolff@digia.com>
Reviewed-by: J-P Nurmi <jpnurmi@digia.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/imports/winextras/plugins.qmltypes | 3 | ||||
-rw-r--r-- | src/imports/winextras/qquickthumbnailtoolbar.cpp | 100 | ||||
-rw-r--r-- | src/imports/winextras/qquickthumbnailtoolbar_p.h | 24 | ||||
-rw-r--r-- | src/winextras/qwinfunctions_p.cpp | 8 | ||||
-rw-r--r-- | src/winextras/qwinfunctions_p.h | 7 | ||||
-rw-r--r-- | src/winextras/qwinthumbnailtoolbar.cpp | 258 | ||||
-rw-r--r-- | src/winextras/qwinthumbnailtoolbar.h | 16 | ||||
-rw-r--r-- | src/winextras/qwinthumbnailtoolbar_p.h | 33 |
8 files changed, 437 insertions, 12 deletions
diff --git a/src/imports/winextras/plugins.qmltypes b/src/imports/winextras/plugins.qmltypes index f5963ce..eb1aa15 100644 --- a/src/imports/winextras/plugins.qmltypes +++ b/src/imports/winextras/plugins.qmltypes @@ -91,6 +91,9 @@ Module { Property { name: "count"; type: "int"; isReadonly: true } Property { name: "data"; type: "QObject"; isList: true; isReadonly: true } Property { name: "buttons"; type: "QQuickThumbnailToolButton"; isList: true; isReadonly: true } + Property { name: "iconicThumbnailSource"; type: "QUrl" } + Property { name: "iconicLivePreviewSource"; type: "QUrl" } + Property { name: "iconicNotificationsEnabled"; type: "bool" } Method { name: "clear" } Method { name: "addButton" diff --git a/src/imports/winextras/qquickthumbnailtoolbar.cpp b/src/imports/winextras/qquickthumbnailtoolbar.cpp index 5558cb8..6f242f9 100644 --- a/src/imports/winextras/qquickthumbnailtoolbar.cpp +++ b/src/imports/winextras/qquickthumbnailtoolbar.cpp @@ -42,6 +42,7 @@ #include "qquickthumbnailtoolbar_p.h" #include "qquickthumbnailtoolbutton_p.h" +#include "qquickiconloader_p.h" #include <QQuickWindow> #include <QQmlEngine> @@ -69,6 +70,10 @@ QT_BEGIN_NAMESPACE QQuickThumbnailToolBar::QQuickThumbnailToolBar(QQuickItem *parent) : QQuickItem(parent) { + connect(&m_toolbar, &QWinThumbnailToolBar::iconicThumbnailPixmapRequested, + this, &QQuickThumbnailToolBar::iconicThumbnailRequested); + connect(&m_toolbar, &QWinThumbnailToolBar::iconicLivePreviewPixmapRequested, + this, &QQuickThumbnailToolBar::iconicLivePreviewRequested); } QQuickThumbnailToolBar::~QQuickThumbnailToolBar() @@ -119,6 +124,101 @@ void QQuickThumbnailToolBar::clear() emit buttonsChanged(); } +/*! + \qmlsignal ThumbnailToolBar::iconicThumbnailRequested() + + This signal is emitted when the operating system requests a new iconic thumbnail pixmap, + typically when the thumbnail is shown. + + \since 5.4 +*/ + +/*! + \qmlsignal ThumbnailToolBar::iconicLivePreviewRequested() + + 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 +*/ + +/*! + \qmlproperty bool ThumbnailToolBar::iconicNotificationsEnabled + + This property holds whether the signals iconicThumbnailRequested() + or iconicLivePreviewRequested() will be emitted. + \since 5.4 + */ +bool QQuickThumbnailToolBar::iconicNotificationsEnabled() const +{ + return m_toolbar.iconicPixmapNotificationsEnabled(); +} + +void QQuickThumbnailToolBar::setIconicNotificationsEnabled(bool enabled) +{ + if (enabled != m_toolbar.iconicPixmapNotificationsEnabled()) { + m_toolbar.setIconicPixmapNotificationsEnabled(enabled); + emit iconicNotificationsEnabledChanged(); + } +} + +void QQuickThumbnailToolBar::iconicThumbnailLoaded(const QVariant &value) +{ + m_toolbar.setIconicThumbnailPixmap(value.value<QPixmap>()); +} + +/*! + \qmlproperty url ThumbnailToolBar::iconicThumbnailSource + + The pixmap for use as a thumbnail representation + \since 5.4 + */ +void QQuickThumbnailToolBar::setIconicThumbnailSource(const QUrl &source) +{ + if (source == m_iconicThumbnailSource) + return; + + if (source.isEmpty()) { + m_toolbar.setIconicThumbnailPixmap(QPixmap()); + m_iconicThumbnailSource = source; + emit iconicThumbnailSourceChanged(); + } + + if (QQuickIconLoader::load(source, qmlEngine(this), QVariant::Pixmap, QSize(), + this, &QQuickThumbnailToolBar::iconicThumbnailLoaded) != QQuickIconLoader::LoadError) { + m_iconicThumbnailSource = source; + emit iconicThumbnailSourceChanged(); + } +} + +void QQuickThumbnailToolBar::iconicLivePreviewLoaded(const QVariant &value) +{ + m_toolbar.setIconicLivePreviewPixmap(value.value<QPixmap>()); +} + +/*! + \qmlproperty url ThumbnailToolBar::iconicLivePreviewSource + + The pixmap for use as a live (peek) preview when tabbing into the application. + \since 5.4 + */ +void QQuickThumbnailToolBar::setIconicLivePreviewSource(const QUrl &source) +{ + if (source == m_iconicLivePreviewSource) + return; + + if (source.isEmpty()) { + m_toolbar.setIconicLivePreviewPixmap(QPixmap()); + m_iconicLivePreviewSource = source; + emit iconicLivePreviewSourceChanged(); + } + + if (QQuickIconLoader::load(source, qmlEngine(this), QVariant::Pixmap, QSize(), + this, &QQuickThumbnailToolBar::iconicLivePreviewLoaded) != QQuickIconLoader::LoadError) { + m_iconicLivePreviewSource = source; + emit iconicLivePreviewSourceChanged(); + } +} + void QQuickThumbnailToolBar::itemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &data) { if (change == ItemSceneChange) diff --git a/src/imports/winextras/qquickthumbnailtoolbar_p.h b/src/imports/winextras/qquickthumbnailtoolbar_p.h index 6a80d80..8599a63 100644 --- a/src/imports/winextras/qquickthumbnailtoolbar_p.h +++ b/src/imports/winextras/qquickthumbnailtoolbar_p.h @@ -45,9 +45,12 @@ #include <QQuickItem> #include <QWinThumbnailToolBar> +#include <QUrl> QT_BEGIN_NAMESPACE +class QVariant; + class QQuickThumbnailToolButton; class QQuickThumbnailToolBar : public QQuickItem @@ -56,6 +59,9 @@ class QQuickThumbnailToolBar : public QQuickItem Q_PROPERTY(int count READ count NOTIFY countChanged) Q_PROPERTY(QQmlListProperty<QObject> data READ data) Q_PROPERTY(QQmlListProperty<QQuickThumbnailToolButton> buttons READ buttons NOTIFY buttonsChanged) + Q_PROPERTY(bool iconicNotificationsEnabled READ iconicNotificationsEnabled WRITE setIconicNotificationsEnabled NOTIFY iconicNotificationsEnabledChanged) + Q_PROPERTY(QUrl iconicThumbnailSource READ iconicThumbnailSource WRITE setIconicThumbnailSource NOTIFY iconicThumbnailSourceChanged) + Q_PROPERTY(QUrl iconicLivePreviewSource READ iconicLivePreviewSource WRITE setIconicLivePreviewSource NOTIFY iconicLivePreviewSourceChanged) Q_CLASSINFO("DefaultProperty", "data") public: @@ -70,12 +76,28 @@ public: Q_INVOKABLE void addButton(QQuickThumbnailToolButton *button); Q_INVOKABLE void removeButton(QQuickThumbnailToolButton *button); + bool iconicNotificationsEnabled() const; + void setIconicNotificationsEnabled(bool); + QUrl iconicThumbnailSource() const { return m_iconicThumbnailSource; } + void setIconicThumbnailSource(const QUrl &); + QUrl iconicLivePreviewSource() const { return m_iconicLivePreviewSource; } + void setIconicLivePreviewSource(const QUrl &); + public Q_SLOTS: void clear(); Q_SIGNALS: void countChanged(); void buttonsChanged(); + void iconicNotificationsEnabledChanged(); + void iconicThumbnailSourceChanged(); + void iconicThumbnailRequested(); + void iconicLivePreviewSourceChanged(); + void iconicLivePreviewRequested(); + +private Q_SLOTS: + void iconicThumbnailLoaded(const QVariant &); + void iconicLivePreviewLoaded(const QVariant &); protected: void itemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &data); @@ -87,6 +109,8 @@ private: QWinThumbnailToolBar m_toolbar; QList<QQuickThumbnailToolButton *> m_buttons; + QUrl m_iconicThumbnailSource; + QUrl m_iconicLivePreviewSource; }; QT_END_NAMESPACE diff --git a/src/winextras/qwinfunctions_p.cpp b/src/winextras/qwinfunctions_p.cpp index 1bb0d32..452685f 100644 --- a/src/winextras/qwinfunctions_p.cpp +++ b/src/winextras/qwinfunctions_p.cpp @@ -66,6 +66,14 @@ void QtDwmApiDll::resolve() (DwmIsCompositionEnabled) GetProcAddress(dwmapi, "DwmIsCompositionEnabled"); dwmEnableComposition = (DwmEnableComposition) GetProcAddress(dwmapi, "DwmEnableComposition"); + if (QSysInfo::windowsVersion() >= QSysInfo::WV_WINDOWS7) { + dwmSetIconicThumbnail = + (DwmSetIconicThumbnail) GetProcAddress(dwmapi, "DwmSetIconicThumbnail"); + dwmSetIconicLivePreviewBitmap = + (DwmSetIconicLivePreviewBitmap) GetProcAddress(dwmapi, "DwmSetIconicLivePreviewBitmap"); + dwmInvalidateIconicBitmaps = + (DwmInvalidateIconicBitmaps) GetProcAddress(dwmapi, "DwmInvalidateIconicBitmaps"); + } } } diff --git a/src/winextras/qwinfunctions_p.h b/src/winextras/qwinfunctions_p.h index 744eae9..0cbd0ec 100644 --- a/src/winextras/qwinfunctions_p.h +++ b/src/winextras/qwinfunctions_p.h @@ -99,11 +99,15 @@ struct QtDwmApiDll typedef HRESULT (STDAPICALLTYPE *DwmEnableBlurBehindWindow)(HWND, const qt_DWM_BLURBEHIND *); typedef HRESULT (STDAPICALLTYPE *DwmIsCompositionEnabled)(BOOL *); typedef HRESULT (STDAPICALLTYPE *DwmEnableComposition)(UINT); + typedef HRESULT (STDAPICALLTYPE *DwmSetIconicThumbnail)(HWND, HBITMAP, DWORD); + typedef HRESULT (STDAPICALLTYPE *DwmSetIconicLivePreviewBitmap)(HWND, HBITMAP, POINT *, DWORD); + typedef HRESULT (STDAPICALLTYPE *DwmInvalidateIconicBitmaps)(HWND); QtDwmApiDll() : dwmGetColorizationColor(0), dwmSetWindowAttribute(0), dwmGetWindowAttribute(0) , dwmExtendFrameIntoClientArea(0), dwmEnableBlurBehindWindow(0) , dwmIsCompositionEnabled(0), dwmEnableComposition(0) + , dwmSetIconicThumbnail(0), dwmSetIconicLivePreviewBitmap(0), dwmInvalidateIconicBitmaps(0) {} void init() @@ -130,6 +134,9 @@ struct QtDwmApiDll DwmEnableBlurBehindWindow dwmEnableBlurBehindWindow; DwmIsCompositionEnabled dwmIsCompositionEnabled; DwmEnableComposition dwmEnableComposition; + DwmSetIconicThumbnail dwmSetIconicThumbnail; + DwmSetIconicLivePreviewBitmap dwmSetIconicLivePreviewBitmap; + DwmInvalidateIconicBitmaps dwmInvalidateIconicBitmaps; }; struct QtShell32Dll diff --git a/src/winextras/qwinthumbnailtoolbar.cpp b/src/winextras/qwinthumbnailtoolbar.cpp index baa4d7c..2748b7a 100644 --- a/src/winextras/qwinthumbnailtoolbar.cpp +++ b/src/winextras/qwinthumbnailtoolbar.cpp @@ -45,6 +45,7 @@ #include "qwinthumbnailtoolbutton.h" #include "qwinthumbnailtoolbutton_p.h" #include "windowsguidsdefs_p.h" +#include "qwinfunctions.h" #include <QWindow> #include <QCoreApplication> @@ -53,14 +54,25 @@ #include "qwinevent.h" #include "qwinfunctions.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; /*! @@ -117,7 +129,10 @@ void QWinThumbnailToolBar::setWindow(QWindow *window) if (d->window != window) { if (d->window) { d->window->removeEventFilter(d); - d->clearToolbar(); + if (d->window->handle()) { + d->clearToolbar(); + setIconicPixmapNotificationsEnabled(false); + } } d->window = window; if (d->window) { @@ -209,6 +224,196 @@ int QWinThumbnailToolBar::count() const return d->buttonList.size(); } +void QWinThumbnailToolBarPrivate::updateIconicPixmapsEnabled(bool invalidate) +{ + Q_Q(QWinThumbnailToolBar); + qtDwmApiDll.init(); + const HWND hwnd = handle(); + if (!hwnd) { + qWarning() << Q_FUNC_INFO << "invoked with hwnd=0"; + return; + } + if (!qtDwmApiDll.dwmInvalidateIconicBitmaps) + return; + const bool enabled = iconicThumbnail || iconicLivePreview; + q->setIconicPixmapNotificationsEnabled(enabled); + if (enabled && invalidate) { + const HRESULT hr = qtDwmApiDll.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 = 0; + } +} + +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 0; + 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 || !qtDwmApiDll.dwmGetWindowAttribute) + return false; + qtDwmApiDll.init(); + return qtDwmApiDll.dwmGetWindowAttribute && hwnd + && 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; + } + qtDwmApiDll.init(); + if (!qtDwmApiDll.dwmSetWindowAttribute || 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) +{ + qtDwmApiDll.init(); + if (!qtDwmApiDll.dwmSetIconicThumbnail || !iconicThumbnail) + return; + const QSize maxSize(HIWORD(message->lParam), LOWORD(message->lParam)); + if (const HBITMAP bitmap = iconicThumbnail.bitmap(maxSize)) { + const HRESULT hr = qtDwmApiDll.dwmSetIconicThumbnail(message->hwnd, bitmap, dWM_SIT_DISPLAYFRAME); + if (FAILED(hr)) + qWarning() << QWinThumbnailToolBarPrivate::msgComFailed("DwmSetIconicThumbnail", hr); + } +} + +inline void QWinThumbnailToolBarPrivate::updateIconicLivePreview(const MSG *message) +{ + qtDwmApiDll.init(); + if (!qtDwmApiDll.dwmSetIconicLivePreviewBitmap || !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 = qtDwmApiDll.dwmSetIconicLivePreviewBitmap(message->hwnd, bitmap, &offset, dWM_SIT_DISPLAYFRAME); + if (FAILED(hr)) + qWarning() << QWinThumbnailToolBarPrivate::msgComFailed("DwmSetIconicLivePreviewBitmap", hr); + } +} + /*! Removes all buttons from the thumbnail toolbar. */ @@ -239,7 +444,8 @@ static inline ITaskbarList4 *createTaskbarList() } QWinThumbnailToolBarPrivate::QWinThumbnailToolBarPrivate() : - QObject(0), updateScheduled(false), window(0), pTbList(createTaskbarList()), q_ptr(0) + QObject(0), updateScheduled(false), window(0), pTbList(createTaskbarList()), q_ptr(0), + withinIconicThumbnailRequest(false), withinIconicLivePreviewRequest(false) { buttonList.reserve(windowsLimitedThumbbarSize); QCoreApplication::instance()->installNativeEventFilter(this); @@ -252,6 +458,16 @@ QWinThumbnailToolBarPrivate::~QWinThumbnailToolBarPrivate() 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()) : HWND(0); +} + void QWinThumbnailToolBarPrivate::initToolbar() { #if !defined(_MSC_VER) || _MSC_VER >= 1600 @@ -259,7 +475,7 @@ void QWinThumbnailToolBarPrivate::initToolbar() return; THUMBBUTTON buttons[windowsLimitedThumbbarSize]; initButtons(buttons); - HRESULT hresult = pTbList->ThumbBarAddButtons(reinterpret_cast<HWND>(window->winId()), windowsLimitedThumbbarSize, buttons); + HRESULT hresult = pTbList->ThumbBarAddButtons(handle(), windowsLimitedThumbbarSize, buttons); if (FAILED(hresult)) qWarning() << msgComFailed("ThumbBarAddButtons", hresult); #else @@ -274,7 +490,7 @@ void QWinThumbnailToolBarPrivate::clearToolbar() return; THUMBBUTTON buttons[windowsLimitedThumbbarSize]; initButtons(buttons); - HRESULT hresult = pTbList->ThumbBarUpdateButtons(reinterpret_cast<HWND>(window->winId()), windowsLimitedThumbbarSize, buttons); + HRESULT hresult = pTbList->ThumbBarUpdateButtons(handle(), windowsLimitedThumbbarSize, buttons); if (FAILED(hresult)) qWarning() << msgComFailed("ThumbBarUpdateButtons", hresult); } @@ -301,9 +517,10 @@ void QWinThumbnailToolBarPrivate::_q_updateToolbar() 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(reinterpret_cast<HWND>(window->winId()), windowsLimitedThumbbarSize, buttons); + HRESULT hresult = pTbList->ThumbBarUpdateButtons(handle(), windowsLimitedThumbbarSize, buttons); if (FAILED(hresult)) qWarning() << msgComFailed("ThumbBarUpdateButtons", hresult); + updateIconicPixmapsEnabled(false); freeButtonResources(buttons); } @@ -327,13 +544,30 @@ bool QWinThumbnailToolBarPrivate::eventFilter(QObject *object, QEvent *event) bool QWinThumbnailToolBarPrivate::nativeEventFilter(const QByteArray &, void *message, long *result) { - MSG *msg = static_cast<MSG *>(message); - if (window && msg->message == WM_COMMAND && HIWORD(msg->wParam) == THBN_CLICKED && msg->hwnd == reinterpret_cast<HWND>(window->winId())) { - int buttonId = LOWORD(msg->wParam); - buttonId = buttonId - (windowsLimitedThumbbarSize - qMin(windowsLimitedThumbbarSize, buttonList.size())); - buttonList.at(buttonId)->click(); - if (result) - *result = 0; + 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; diff --git a/src/winextras/qwinthumbnailtoolbar.h b/src/winextras/qwinthumbnailtoolbar.h index c048298..09dfc34 100644 --- a/src/winextras/qwinthumbnailtoolbar.h +++ b/src/winextras/qwinthumbnailtoolbar.h @@ -48,6 +48,7 @@ QT_BEGIN_NAMESPACE +class QPixmap; class QWindow; class QWinThumbnailToolButton; class QWinThumbnailToolBarPrivate; @@ -57,6 +58,9 @@ class Q_WINEXTRAS_EXPORT QWinThumbnailToolBar : public QObject Q_OBJECT Q_PROPERTY(int count READ count STORED false) Q_PROPERTY(QWindow *window READ window WRITE setWindow) + Q_PROPERTY(bool iconicPixmapNotificationsEnabled READ iconicPixmapNotificationsEnabled WRITE setIconicPixmapNotificationsEnabled) + Q_PROPERTY(QPixmap iconicThumbnailPixmap READ iconicThumbnailPixmap WRITE setIconicThumbnailPixmap) + Q_PROPERTY(QPixmap iconicLivePreviewPixmap READ iconicLivePreviewPixmap WRITE setIconicLivePreviewPixmap) public: explicit QWinThumbnailToolBar(QObject *parent = 0); @@ -71,8 +75,20 @@ public: QList<QWinThumbnailToolButton *> buttons() const; int count() const; + bool iconicPixmapNotificationsEnabled() const; + void setIconicPixmapNotificationsEnabled(bool enabled); + + QPixmap iconicThumbnailPixmap() const; + QPixmap iconicLivePreviewPixmap() const; + public Q_SLOTS: void clear(); + void setIconicThumbnailPixmap(const QPixmap &); + void setIconicLivePreviewPixmap(const QPixmap &); + +Q_SIGNALS: + void iconicThumbnailPixmapRequested(); + void iconicLivePreviewPixmapRequested(); private: Q_DISABLE_COPY(QWinThumbnailToolBar) diff --git a/src/winextras/qwinthumbnailtoolbar_p.h b/src/winextras/qwinthumbnailtoolbar_p.h index b799d7c..b7d8eff 100644 --- a/src/winextras/qwinthumbnailtoolbar_p.h +++ b/src/winextras/qwinthumbnailtoolbar_p.h @@ -47,6 +47,7 @@ #include <QtCore/QHash> #include <QtCore/QList> #include <QtGui/QIcon> +#include <QtGui/QPixmap> #include <QtCore/QAbstractNativeEventFilter> #include "winshobjidl_p.h" @@ -56,6 +57,27 @@ QT_BEGIN_NAMESPACE class QWinThumbnailToolBarPrivate : public QObject, QAbstractNativeEventFilter { public: + class IconicPixmapCache + { + public: + IconicPixmapCache() : m_bitmap(0) {} + ~IconicPixmapCache() { deleteBitmap(); } + + operator bool() const { return !m_pixmap.isNull(); } + + QPixmap pixmap() const { return m_pixmap; } + bool setPixmap(const QPixmap &p); + + HBITMAP bitmap(const QSize &maxSize); + + private: + void deleteBitmap(); + + QPixmap m_pixmap; + QSize m_size; + HBITMAP m_bitmap; + }; + QWinThumbnailToolBarPrivate(); ~QWinThumbnailToolBarPrivate(); void initToolbar(); @@ -77,9 +99,20 @@ public: QWindow *window; ITaskbarList4 * const pTbList; + IconicPixmapCache iconicThumbnail; + IconicPixmapCache iconicLivePreview; + private: + bool hasHandle() const; + HWND handle() const; + void updateIconicPixmapsEnabled(bool invalidate); + void updateIconicThumbnail(const MSG *message); + void updateIconicLivePreview(const MSG *message); + QWinThumbnailToolBar *q_ptr; Q_DECLARE_PUBLIC(QWinThumbnailToolBar) + bool withinIconicThumbnailRequest; + bool withinIconicLivePreviewRequest; }; QT_END_NAMESPACE |