Windows: Added support for large icons to QFileIconProvider.

Added code using image lists to windows theme.

Initial-patch-by: Max Desyatov <max.desyatov@gmail.com>

Task-number: QTBUG-4970
Change-Id: I6e82f4edec60e456d0b1759bb1771955edb94491
Reviewed-by: Oliver Wolff <oliver.wolff@digia.com>
bb10
Friedemann Kleint 2013-09-06 08:43:21 +02:00 committed by The Qt Project
parent 6c88be2af2
commit 87ff0af425
3 changed files with 81 additions and 6 deletions

View File

@ -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;

View File

@ -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

View File

@ -48,6 +48,11 @@
#ifdef Q_OS_WINCE
# include "qplatformfunctions_wince.h"
# include "winuser.h"
#else
# include <commctrl.h>
# include <objbase.h>
# include <commoncontrols.h>
# include <shellapi.h>
#endif
#include <QtCore/QVariant>
@ -65,6 +70,10 @@
#include <algorithm>
#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<int> 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);