From 87ff0af425656d12c4766a57db60674d63ffa584 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Fri, 6 Sep 2013 08:43:21 +0200 Subject: Windows: Added support for large icons to QFileIconProvider. Added code using image lists to windows theme. Initial-patch-by: Max Desyatov Task-number: QTBUG-4970 Change-Id: I6e82f4edec60e456d0b1759bb1771955edb94491 Reviewed-by: Oliver Wolff --- src/plugins/platforms/windows/qwindowscontext.cpp | 2 + src/plugins/platforms/windows/qwindowscontext.h | 2 + src/plugins/platforms/windows/qwindowstheme.cpp | 83 +++++++++++++++++++++-- 3 files changed, 81 insertions(+), 6 deletions(-) (limited to 'src/plugins/platforms') diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp index c676ca3c46..8dab1e2b1c 100644 --- a/src/plugins/platforms/windows/qwindowscontext.cpp +++ b/src/plugins/platforms/windows/qwindowscontext.cpp @@ -218,6 +218,7 @@ bool QWindowsUser32DLL::initTouch() QWindowsShell32DLL::QWindowsShell32DLL() : sHCreateItemFromParsingName(0) , sHGetStockIconInfo(0) + , sHGetImageList(0) { } @@ -226,6 +227,7 @@ void QWindowsShell32DLL::init() QSystemLibrary library(QStringLiteral("shell32")); sHCreateItemFromParsingName = (SHCreateItemFromParsingName)(library.resolve("SHCreateItemFromParsingName")); sHGetStockIconInfo = (SHGetStockIconInfo)library.resolve("SHGetStockIconInfo"); + sHGetImageList = (SHGetImageList)library.resolve("SHGetImageList"); } QWindowsUser32DLL QWindowsContext::user32dll; diff --git a/src/plugins/platforms/windows/qwindowscontext.h b/src/plugins/platforms/windows/qwindowscontext.h index 0d3476e00f..173df58570 100644 --- a/src/plugins/platforms/windows/qwindowscontext.h +++ b/src/plugins/platforms/windows/qwindowscontext.h @@ -108,9 +108,11 @@ struct QWindowsShell32DLL typedef HRESULT (WINAPI *SHCreateItemFromParsingName)(PCWSTR, IBindCtx *, const GUID&, void **); typedef HRESULT (WINAPI *SHGetStockIconInfo)(int , int , _SHSTOCKICONINFO *); + typedef HRESULT (WINAPI *SHGetImageList)(int, REFIID , void **); SHCreateItemFromParsingName sHCreateItemFromParsingName; SHGetStockIconInfo sHGetStockIconInfo; + SHGetImageList sHGetImageList; }; #endif // Q_OS_WINCE diff --git a/src/plugins/platforms/windows/qwindowstheme.cpp b/src/plugins/platforms/windows/qwindowstheme.cpp index 1710fd419a..498bd509fa 100644 --- a/src/plugins/platforms/windows/qwindowstheme.cpp +++ b/src/plugins/platforms/windows/qwindowstheme.cpp @@ -48,6 +48,11 @@ #ifdef Q_OS_WINCE # include "qplatformfunctions_wince.h" # include "winuser.h" +#else +# include +# include +# include +# include #endif #include @@ -65,6 +70,10 @@ #include +#if defined(__IImageList_INTERFACE_DEFINED__) && defined(__IID_DEFINED__) +# define USE_IIMAGELIST +#endif + QT_BEGIN_NAMESPACE static inline QTextStream& operator<<(QTextStream &str, const QColor &c) @@ -357,6 +366,11 @@ QVariant QWindowsTheme::themeHint(ThemeHint hint) const case IconPixmapSizes: { QList sizes; sizes << 16 << 32; +#ifdef USE_IIMAGELIST + sizes << 48; // sHIL_EXTRALARGE + if (QSysInfo::WindowsVersion >= QSysInfo::WV_VISTA) + sizes << 256; // SHIL_JUMBO +#endif // USE_IIMAGELIST return QVariant::fromValue(sizes); } case DialogSnapToDefaultButton: @@ -574,11 +588,24 @@ QPixmap QWindowsTheme::standardPixmap(StandardPixmap sp, const QSizeF &size) con return QPlatformTheme::standardPixmap(sp, size); } -static QString dirIconPixmapCacheKey(int iIcon, int iconSize) +enum { // Shell image list ids + sHIL_EXTRALARGE = 0x2, // 48x48 or user-defined + sHIL_JUMBO = 0x4 // 256x256 (Vista or later) +}; + +static QString dirIconPixmapCacheKey(int iIcon, int iconSize, int imageListSize) { QString key = QLatin1String("qt_dir_") + QString::number(iIcon); if (iconSize == SHGFI_LARGEICON) key += QLatin1Char('l'); + switch (imageListSize) { + case sHIL_EXTRALARGE: + key += QLatin1Char('e'); + break; + case sHIL_JUMBO: + key += QLatin1Char('j'); + break; + } return key; } @@ -602,6 +629,38 @@ public: void operator delete (void *) {} }; +// Shell image list helper functions. + +static QPixmap pixmapFromShellImageList(int iImageList, const SHFILEINFO &info) +{ + QPixmap result; +#ifdef USE_IIMAGELIST + // For MinGW: + static const IID iID_IImageList = {0x46eb5926, 0x582e, 0x4017, {0x9f, 0xdf, 0xe8, 0x99, 0x8d, 0xaa, 0x9, 0x50}}; + + if (!QWindowsContext::shell32dll.sHGetImageList) + return result; + if (iImageList == sHIL_JUMBO && QSysInfo::WindowsVersion < QSysInfo::WV_VISTA) + return result; + + IImageList *imageList = 0; + HRESULT hr = QWindowsContext::shell32dll.sHGetImageList(iImageList, iID_IImageList, (void **)&imageList); + if (hr != S_OK) + return result; + HICON hIcon; + hr = imageList->GetIcon(info.iIcon, ILD_TRANSPARENT, &hIcon); + if (hr == S_OK) { + result = qt_pixmapFromWinHICON(hIcon); + DestroyIcon(hIcon); + } + imageList->Release(); +#else + Q_UNUSED(iImageList) + Q_UNUSED(info) +#endif // USE_IIMAGELIST + return result; +} + QPixmap QWindowsTheme::fileIconPixmap(const QFileInfo &fileInfo, const QSizeF &size, QPlatformTheme::IconOptions iconOptions) const { @@ -617,15 +676,21 @@ QPixmap QWindowsTheme::fileIconPixmap(const QFileInfo &fileInfo, const QSizeF &s QPixmap pixmap; const QString filePath = QDir::toNativeSeparators(fileInfo.filePath()); - int iconSize = size.width() > 16 ? SHGFI_LARGEICON : SHGFI_SMALLICON; - + const int width = size.width(); + const int iconSize = width > 16 ? SHGFI_LARGEICON : SHGFI_SMALLICON; + const int requestedImageListSize = +#ifdef USE_IIMAGELIST + width > 48 ? sHIL_JUMBO : (width > 32 ? sHIL_EXTRALARGE : 0); +#else + 0; +#endif // !USE_IIMAGELIST bool cacheableDirIcon = fileInfo.isDir() && !fileInfo.isRoot(); if (cacheableDirIcon) { QMutexLocker locker(&mx); int iIcon = (useDefaultFolderIcon && defaultFolderIIcon) ? defaultFolderIIcon : **dirIconEntryCache.object(filePath); if (iIcon) { - QPixmapCache::find(dirIconPixmapCacheKey(iIcon, iconSize), pixmap); + QPixmapCache::find(dirIconPixmapCacheKey(iIcon, iconSize, requestedImageListSize), pixmap); if (pixmap.isNull()) // Let's keep both caches in sync dirIconEntryCache.remove(filePath); else @@ -659,7 +724,7 @@ QPixmap QWindowsTheme::fileIconPixmap(const QFileInfo &fileInfo, const QSizeF &s defaultFolderIIcon = info.iIcon; //using the unique icon index provided by windows save us from duplicate keys - key = dirIconPixmapCacheKey(info.iIcon, iconSize); + key = dirIconPixmapCacheKey(info.iIcon, iconSize, requestedImageListSize); QPixmapCache::find(key, pixmap); if (!pixmap.isNull()) { QMutexLocker locker(&mx); @@ -668,7 +733,13 @@ QPixmap QWindowsTheme::fileIconPixmap(const QFileInfo &fileInfo, const QSizeF &s } if (pixmap.isNull()) { - pixmap = qt_pixmapFromWinHICON(info.hIcon); + if (requestedImageListSize) { + pixmap = pixmapFromShellImageList(requestedImageListSize, info); + if (pixmap.isNull() && requestedImageListSize == sHIL_JUMBO) + pixmap = pixmapFromShellImageList(sHIL_EXTRALARGE, info); + } + if (pixmap.isNull()) + pixmap = qt_pixmapFromWinHICON(info.hIcon); if (!pixmap.isNull()) { if (cacheableDirIcon) { QMutexLocker locker(&mx); -- cgit v1.2.3