diff options
Diffstat (limited to 'src/plugins/platforms/windows/qwindowstheme.cpp')
-rw-r--r-- | src/plugins/platforms/windows/qwindowstheme.cpp | 123 |
1 files changed, 109 insertions, 14 deletions
diff --git a/src/plugins/platforms/windows/qwindowstheme.cpp b/src/plugins/platforms/windows/qwindowstheme.cpp index 9f6e6b18e7..eb1bbd1ab0 100644 --- a/src/plugins/platforms/windows/qwindowstheme.cpp +++ b/src/plugins/platforms/windows/qwindowstheme.cpp @@ -54,6 +54,13 @@ #ifdef Q_OS_WINCE # include "qplatformfunctions_wince.h" # include "winuser.h" +#else +# include <commctrl.h> +# include <objbase.h> +# ifndef Q_CC_MINGW +# include <commoncontrols.h> +# endif +# include <shellapi.h> #endif #include <QtCore/QVariant> @@ -69,6 +76,12 @@ #include <qpa/qwindowsysteminterface.h> #include <private/qsystemlibrary_p.h> +#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) @@ -290,8 +303,8 @@ QWindowsTheme *QWindowsTheme::m_instance = 0; QWindowsTheme::QWindowsTheme() { m_instance = this; - qFill(m_fonts, m_fonts + NFonts, static_cast<QFont *>(0)); - qFill(m_palettes, m_palettes + NPalettes, static_cast<QPalette *>(0)); + std::fill(m_fonts, m_fonts + NFonts, static_cast<QFont *>(0)); + std::fill(m_palettes, m_palettes + NPalettes, static_cast<QPalette *>(0)); refresh(); } @@ -361,8 +374,15 @@ 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: + return QVariant(booleanSystemParametersInfo(SPI_GETSNAPTODEFBUTTON, false)); default: break; } @@ -372,7 +392,7 @@ QVariant QWindowsTheme::themeHint(ThemeHint hint) const void QWindowsTheme::clearPalettes() { qDeleteAll(m_palettes, m_palettes + NPalettes); - qFill(m_palettes, m_palettes + NPalettes, static_cast<QPalette *>(0)); + std::fill(m_palettes, m_palettes + NPalettes, static_cast<QPalette *>(0)); } void QWindowsTheme::refreshPalettes() @@ -393,7 +413,7 @@ void QWindowsTheme::refreshPalettes() void QWindowsTheme::clearFonts() { qDeleteAll(m_fonts, m_fonts + NFonts); - qFill(m_fonts, m_fonts + NFonts, static_cast<QFont *>(0)); + std::fill(m_fonts, m_fonts + NFonts, static_cast<QFont *>(0)); } void QWindowsTheme::refreshFonts() @@ -410,6 +430,8 @@ void QWindowsTheme::refreshFonts() const QFont messageBoxFont = QWindowsFontDatabase::LOGFONT_to_QFont(ncm.lfMessageFont); const QFont statusFont = QWindowsFontDatabase::LOGFONT_to_QFont(ncm.lfStatusFont); const QFont titleFont = QWindowsFontDatabase::LOGFONT_to_QFont(ncm.lfCaptionFont); + QFont fixedFont(QStringLiteral("Courier New"), messageBoxFont.pointSize()); + fixedFont.setStyleHint(QFont::TypeWriter); LOGFONT lfIconTitleFont; SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(lfIconTitleFont), &lfIconTitleFont, 0); @@ -424,6 +446,7 @@ void QWindowsTheme::refreshFonts() m_fonts[MdiSubWindowTitleFont] = new QFont(titleFont); m_fonts[DockWidgetTitleFont] = new QFont(titleFont); m_fonts[ItemViewFont] = new QFont(iconTitleFont); + m_fonts[FixedFont] = new QFont(fixedFont); if (QWindowsContext::verboseTheming) qDebug() << __FUNCTION__ << '\n' @@ -573,11 +596,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; } @@ -601,7 +637,40 @@ public: void operator delete (void *) {} }; -QPixmap QWindowsTheme::fileIconPixmap(const QFileInfo &fileInfo, const QSizeF &size) const +// 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 { /* We don't use the variable, but by storing it statically, we * ensure CoInitialize is only called once. */ @@ -610,17 +679,26 @@ QPixmap QWindowsTheme::fileIconPixmap(const QFileInfo &fileInfo, const QSizeF &s static QCache<QString, FakePointer<int> > dirIconEntryCache(1000); static QMutex mx; + static int defaultFolderIIcon = -1; + const bool useDefaultFolderIcon = iconOptions & QPlatformTheme::DontUseCustomDirectoryIcons; 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 = **dirIconEntryCache.object(filePath); + int iIcon = (useDefaultFolderIcon && defaultFolderIIcon >= 0) ? 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 @@ -635,15 +713,26 @@ QPixmap QWindowsTheme::fileIconPixmap(const QFileInfo &fileInfo, const QSizeF &s #else iconSize|SHGFI_SYSICONINDEX; #endif // Q_OS_WINCE - unsigned long val = SHGetFileInfo((const wchar_t *)filePath.utf16(), 0, - &info, sizeof(SHFILEINFO), flags); + unsigned long val = 0; + if (cacheableDirIcon && useDefaultFolderIcon) { + flags |= SHGFI_USEFILEATTRIBUTES; + val = SHGetFileInfo(L"dummy", + FILE_ATTRIBUTE_DIRECTORY, + &info, sizeof(SHFILEINFO), flags); + } else { + val = SHGetFileInfo(reinterpret_cast<const wchar_t *>(filePath.utf16()), 0, + &info, sizeof(SHFILEINFO), flags); + } // Even if GetFileInfo returns a valid result, hIcon can be empty in some cases if (val && info.hIcon) { QString key; if (cacheableDirIcon) { + if (useDefaultFolderIcon && defaultFolderIIcon < 0) + 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); @@ -652,7 +741,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); |