diff options
Diffstat (limited to 'src/plugins')
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoatheme.h | 2 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoatheme.mm | 144 | ||||
-rw-r--r-- | src/plugins/platforms/windows/qtwindows_additional.h | 15 | ||||
-rw-r--r-- | src/plugins/platforms/windows/qwindowscontext.cpp | 5 | ||||
-rw-r--r-- | src/plugins/platforms/windows/qwindowscontext.h | 3 | ||||
-rw-r--r-- | src/plugins/platforms/windows/qwindowstheme.cpp | 230 | ||||
-rw-r--r-- | src/plugins/platforms/windows/qwindowstheme.h | 3 |
7 files changed, 401 insertions, 1 deletions
diff --git a/src/plugins/platforms/cocoa/qcocoatheme.h b/src/plugins/platforms/cocoa/qcocoatheme.h index a747a82d09..0ff160957f 100644 --- a/src/plugins/platforms/cocoa/qcocoatheme.h +++ b/src/plugins/platforms/cocoa/qcocoatheme.h @@ -67,6 +67,8 @@ public: const QPalette *palette(Palette type = SystemPalette) const; const QFont *font(Font type = SystemFont) const; + QPixmap standardPixmap(StandardPixmap sp, const QSizeF &size) const; + QPixmap fileIconPixmap(const QFileInfo &fileInfo, const QSizeF &size) const; QVariant themeHint(ThemeHint hint) const; diff --git a/src/plugins/platforms/cocoa/qcocoatheme.mm b/src/plugins/platforms/cocoa/qcocoatheme.mm index ddb550dd5f..967d65faec 100644 --- a/src/plugins/platforms/cocoa/qcocoatheme.mm +++ b/src/plugins/platforms/cocoa/qcocoatheme.mm @@ -54,7 +54,9 @@ #include "qcocoamenu.h" #include "qcocoamenubar.h" +#include <QtCore/qfileinfo.h> #include <QtGui/private/qguiapplication_p.h> +#include <QtGui/qpainter.h> #include <qpa/qplatformintegration.h> #include <qpa/qplatformnativeinterface.h> @@ -135,6 +137,143 @@ const QFont *QCocoaTheme::font(Font type) const return m_fonts.value(type, 0); } +// Defined in qpaintengine_mac.mm +extern CGContextRef qt_mac_cg_context(const QPaintDevice *pdev); + +//! \internal +QPixmap qt_mac_convert_iconref(const IconRef icon, int width, int height) +{ + QPixmap ret(width, height); + ret.fill(QColor(0, 0, 0, 0)); + + CGRect rect = CGRectMake(0, 0, width, height); + + CGContextRef ctx = qt_mac_cg_context(&ret); + CGAffineTransform old_xform = CGContextGetCTM(ctx); + CGContextConcatCTM(ctx, CGAffineTransformInvert(old_xform)); + CGContextConcatCTM(ctx, CGAffineTransformIdentity); + + ::RGBColor b; + b.blue = b.green = b.red = 255*255; + PlotIconRefInContext(ctx, &rect, kAlignNone, kTransformNone, &b, kPlotIconRefNormalFlags, icon); + CGContextRelease(ctx); + return ret; +} + +QPixmap QCocoaTheme::standardPixmap(StandardPixmap sp, const QSizeF &size) const +{ + OSType iconType = 0; + switch (sp) { + case MessageBoxQuestion: + iconType = kQuestionMarkIcon; + break; + case MessageBoxInformation: + iconType = kAlertNoteIcon; + break; + case MessageBoxWarning: + iconType = kAlertCautionIcon; + break; + case MessageBoxCritical: + iconType = kAlertStopIcon; + break; + case DesktopIcon: + iconType = kDesktopIcon; + break; + case TrashIcon: + iconType = kTrashIcon; + break; + case ComputerIcon: + iconType = kComputerIcon; + break; + case DriveFDIcon: + iconType = kGenericFloppyIcon; + break; + case DriveHDIcon: + iconType = kGenericHardDiskIcon; + break; + case DriveCDIcon: + case DriveDVDIcon: + iconType = kGenericCDROMIcon; + break; + case DriveNetIcon: + iconType = kGenericNetworkIcon; + break; + case DirOpenIcon: + iconType = kOpenFolderIcon; + break; + case DirClosedIcon: + case DirLinkIcon: + iconType = kGenericFolderIcon; + break; + case FileLinkIcon: + case FileIcon: + iconType = kGenericDocumentIcon; + break; + default: + break; + } + if (iconType != 0) { + QPixmap pixmap; + IconRef icon; + IconRef overlayIcon = 0; + if (iconType != kGenericApplicationIcon) { + GetIconRef(kOnSystemDisk, kSystemIconsCreator, iconType, &icon); + } else { + FSRef fsRef; + ProcessSerialNumber psn = { 0, kCurrentProcess }; + GetProcessBundleLocation(&psn, &fsRef); + GetIconRefFromFileInfo(&fsRef, 0, 0, 0, 0, kIconServicesNormalUsageFlag, &icon, 0); + if (sp == MessageBoxCritical) { + overlayIcon = icon; + GetIconRef(kOnSystemDisk, kSystemIconsCreator, kAlertCautionIcon, &icon); + } + } + + if (icon) { + pixmap = qt_mac_convert_iconref(icon, size.width(), size.height()); + ReleaseIconRef(icon); + } + + if (overlayIcon) { + QSizeF littleSize = size / 2; + QPixmap overlayPix = qt_mac_convert_iconref(overlayIcon, littleSize.width(), littleSize.height()); + QPainter painter(&pixmap); + painter.drawPixmap(littleSize.width(), littleSize.height(), overlayPix); + ReleaseIconRef(overlayIcon); + } + + return pixmap; + } + + return QPlatformTheme::standardPixmap(sp, size); +} + +QPixmap QCocoaTheme::fileIconPixmap(const QFileInfo &fileInfo, const QSizeF &size) const +{ + FSRef macRef; + OSStatus status = FSPathMakeRef(reinterpret_cast<const UInt8*>(fileInfo.canonicalFilePath().toUtf8().constData()), + &macRef, 0); + if (status != noErr) + return QPixmap(); + FSCatalogInfo info; + HFSUniStr255 macName; + status = FSGetCatalogInfo(&macRef, kIconServicesCatalogInfoMask, &info, &macName, 0, 0); + if (status != noErr) + return QPixmap(); + IconRef iconRef; + SInt16 iconLabel; + status = GetIconRefFromFileInfo(&macRef, macName.length, macName.unicode, + kIconServicesCatalogInfoMask, &info, kIconServicesNormalUsageFlag, + &iconRef, &iconLabel); + if (status != noErr) + return QPixmap(); + + QPixmap pixmap = qt_mac_convert_iconref(iconRef, size.width(), size.height()); + ReleaseIconRef(iconRef); + + return pixmap; +} + QVariant QCocoaTheme::themeHint(ThemeHint hint) const { switch (hint) { @@ -146,6 +285,11 @@ QVariant QCocoaTheme::themeHint(ThemeHint hint) const return QVariant(int(MacKeyboardScheme)); case TabAllWidgets: return QVariant(bool([[NSApplication sharedApplication] isFullKeyboardAccessEnabled])); + case IconPixmapSizes: { + QList<int> sizes; + sizes << 16 << 32 << 64 << 128; + return QVariant::fromValue(sizes); + } default: break; } diff --git a/src/plugins/platforms/windows/qtwindows_additional.h b/src/plugins/platforms/windows/qtwindows_additional.h index f5ea2cf6bf..3566367e41 100644 --- a/src/plugins/platforms/windows/qtwindows_additional.h +++ b/src/plugins/platforms/windows/qtwindows_additional.h @@ -83,6 +83,21 @@ #define CHILDID_SELF 0 #define WM_GETOBJECT 0x003D +#ifndef SIID_SHIELD // Shell structures for icons. +typedef struct _SHSTOCKICONINFO +{ + DWORD cbSize; + HICON hIcon; + int iSysImageIndex; + int iIcon; + WCHAR szPath[MAX_PATH]; +} SHSTOCKICONINFO; + +# define SIID_SHIELD 77 +# define SHGFI_ADDOVERLAYS 0x20 +# define SHGFI_OVERLAYINDEX 0x40 +#endif // SIID_SHIELD + #if !defined(__MINGW64_VERSION_MAJOR) #define STATE_SYSTEM_HASPOPUP 0x40000000 diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp index 98c17deba9..3d4871d7a2 100644 --- a/src/plugins/platforms/windows/qwindowscontext.cpp +++ b/src/plugins/platforms/windows/qwindowscontext.cpp @@ -210,7 +210,9 @@ bool QWindowsUser32DLL::initTouch() \ingroup qt-lighthouse-win */ -QWindowsShell32DLL::QWindowsShell32DLL() : sHCreateItemFromParsingName(0) +QWindowsShell32DLL::QWindowsShell32DLL() + : sHCreateItemFromParsingName(0) + , sHGetStockIconInfo(0) { } @@ -218,6 +220,7 @@ void QWindowsShell32DLL::init() { QSystemLibrary library(QStringLiteral("shell32")); sHCreateItemFromParsingName = (SHCreateItemFromParsingName)(library.resolve("SHCreateItemFromParsingName")); + sHGetStockIconInfo = (SHGetStockIconInfo)library.resolve("SHGetStockIconInfo"); } QWindowsUser32DLL QWindowsContext::user32dll; diff --git a/src/plugins/platforms/windows/qwindowscontext.h b/src/plugins/platforms/windows/qwindowscontext.h index 450d6c8f4b..78cd104fbe 100644 --- a/src/plugins/platforms/windows/qwindowscontext.h +++ b/src/plugins/platforms/windows/qwindowscontext.h @@ -49,6 +49,7 @@ #include <QtCore/QSharedPointer> struct IBindCtx; +struct _SHSTOCKICONINFO; QT_BEGIN_NAMESPACE @@ -99,8 +100,10 @@ struct QWindowsShell32DLL inline void init(); typedef HRESULT (WINAPI *SHCreateItemFromParsingName)(PCWSTR, IBindCtx *, const GUID&, void **); + typedef HRESULT (WINAPI *SHGetStockIconInfo)(int , int , _SHSTOCKICONINFO *); SHCreateItemFromParsingName sHCreateItemFromParsingName; + SHGetStockIconInfo sHGetStockIconInfo; }; #endif // Q_OS_WINCE diff --git a/src/plugins/platforms/windows/qwindowstheme.cpp b/src/plugins/platforms/windows/qwindowstheme.cpp index 7b3ffc633f..748ba09a90 100644 --- a/src/plugins/platforms/windows/qwindowstheme.cpp +++ b/src/plugins/platforms/windows/qwindowstheme.cpp @@ -55,9 +55,13 @@ #include <QtCore/QDebug> #include <QtCore/QTextStream> #include <QtCore/QSysInfo> +#include <QtCore/QCache> #include <QtGui/QPalette> #include <QtGui/QGuiApplication> +#include <QtGui/QPainter> +#include <QtGui/QPixmapCache> #include <qpa/qwindowsysteminterface.h> +#include <private/qsystemlibrary_p.h> QT_BEGIN_NAMESPACE @@ -348,6 +352,11 @@ QVariant QWindowsTheme::themeHint(ThemeHint hint) const return QVariant(int(WindowsKeyboardScheme)); case UiEffects: return QVariant(uiEffects()); + case IconPixmapSizes: { + QList<int> sizes; + sizes << 16 << 32; + return QVariant::fromValue(sizes); + } default: break; } @@ -433,4 +442,225 @@ void QWindowsTheme::windowsThemeChanged(QWindow * window) QWindowSystemInterface::handleThemeChange(window); } +// Defined in qpixmap_win.cpp +Q_GUI_EXPORT QPixmap qt_pixmapFromWinHICON(HICON icon); + +static QPixmap loadIconFromShell32(int resourceId, QSizeF size) +{ +#ifdef Q_OS_WINCE + HMODULE hmod = LoadLibrary(L"ceshell"); +#else + HMODULE hmod = QSystemLibrary::load(L"shell32"); +#endif + if (hmod) { + HICON iconHandle = (HICON)LoadImage(hmod, MAKEINTRESOURCE(resourceId), IMAGE_ICON, size.width(), size.height(), 0); + if (iconHandle) { + QPixmap iconpixmap = qt_pixmapFromWinHICON(iconHandle); + DestroyIcon(iconHandle); + return iconpixmap; + } + } + return QPixmap(); +} + +QPixmap QWindowsTheme::standardPixmap(StandardPixmap sp, const QSizeF &size) const +{ + int resourceId = -1; + LPCTSTR iconName = 0; + switch (sp) { + case DriveCDIcon: + case DriveDVDIcon: + resourceId = 12; + break; + case DriveNetIcon: + resourceId = 10; + break; + case DriveHDIcon: + resourceId = 9; + break; + case DriveFDIcon: + resourceId = 7; + break; + case FileIcon: + case FileLinkIcon: + resourceId = 1; + break; + case DirIcon: + case DirLinkIcon: + case DirClosedIcon: + resourceId = 4; + break; + case DesktopIcon: + resourceId = 35; + break; + case ComputerIcon: + resourceId = 16; + break; + case DirOpenIcon: + case DirLinkOpenIcon: + resourceId = 5; + break; + case FileDialogNewFolder: + resourceId = 319; + break; + case DirHomeIcon: + resourceId = 235; + break; + case TrashIcon: + resourceId = 191; + break; + case MessageBoxInformation: + iconName = IDI_INFORMATION; + break; + case MessageBoxWarning: + iconName = IDI_WARNING; + break; + case MessageBoxCritical: + iconName = IDI_ERROR; + break; + case MessageBoxQuestion: + iconName = IDI_QUESTION; + break; + case VistaShield: + if (QSysInfo::WindowsVersion >= QSysInfo::WV_VISTA + && (QSysInfo::WindowsVersion & QSysInfo::WV_NT_based)) { + if (!QWindowsContext::shell32dll.sHGetStockIconInfo) + return QPixmap(); + QPixmap pixmap; + SHSTOCKICONINFO iconInfo; + memset(&iconInfo, 0, sizeof(iconInfo)); + iconInfo.cbSize = sizeof(iconInfo); + const int iconSize = size.width() > 16 ? SHGFI_LARGEICON : SHGFI_SMALLICON; + if (QWindowsContext::shell32dll.sHGetStockIconInfo(SIID_SHIELD, SHGFI_ICON | iconSize, &iconInfo) == S_OK) { + pixmap = qt_pixmapFromWinHICON(iconInfo.hIcon); + DestroyIcon(iconInfo.hIcon); + return pixmap; + } + } + break; + default: + break; + } + + if (resourceId != -1) { + QPixmap pixmap = loadIconFromShell32(resourceId, size); + if (!pixmap.isNull()) { + if (sp == FileLinkIcon || sp == DirLinkIcon || sp == DirLinkOpenIcon) { + QPainter painter(&pixmap); + QPixmap link = loadIconFromShell32(30, size); + painter.drawPixmap(0, 0, size.width(), size.height(), link); + } + return pixmap; + } + } + + if (iconName) { + HICON iconHandle = LoadIcon(NULL, iconName); + QPixmap pixmap = qt_pixmapFromWinHICON(iconHandle); + DestroyIcon(iconHandle); + if (!pixmap.isNull()) + return pixmap; + } + + return QPlatformTheme::standardPixmap(sp, size); +} + +static QString dirIconPixmapCacheKey(int iIcon, int iconSize) +{ + QString key = QLatin1String("qt_dir_") + QString::number(iIcon); + if (iconSize == SHGFI_LARGEICON) + key += QLatin1Char('l'); + return key; +} + +template <typename T> +class FakePointer +{ +public: + + Q_STATIC_ASSERT_X(sizeof(T) <= sizeof(void *), "FakePointers can only go that far."); + + static FakePointer *create(T thing) + { + return reinterpret_cast<FakePointer *>(thing); + } + + T operator * () const + { + return reinterpret_cast<T>(this); + } + + void operator delete (void *) {} +}; + +QPixmap QWindowsTheme::fileIconPixmap(const QFileInfo &fileInfo, const QSizeF &size) const +{ + /* We don't use the variable, but by storing it statically, we + * ensure CoInitialize is only called once. */ + static HRESULT comInit = CoInitialize(NULL); + Q_UNUSED(comInit); + + static QCache<QString, FakePointer<int> > dirIconEntryCache(1000); + static QMutex mx; + + QPixmap pixmap; + const QString filePath = QDir::toNativeSeparators(fileInfo.filePath()); + int iconSize = size.width() > 16 ? SHGFI_LARGEICON : SHGFI_SMALLICON; + + bool cacheableDirIcon = fileInfo.isDir() && !fileInfo.isRoot(); + if (cacheableDirIcon) { + QMutexLocker locker(&mx); + int iIcon = **dirIconEntryCache.object(filePath); + if (iIcon) { + QPixmapCache::find(dirIconPixmapCacheKey(iIcon, iconSize), pixmap); + if (pixmap.isNull()) // Let's keep both caches in sync + dirIconEntryCache.remove(filePath); + else + return pixmap; + } + } + + SHFILEINFO info; + unsigned int flags = +#ifndef Q_OS_WINCE + SHGFI_ICON|iconSize|SHGFI_SYSICONINDEX|SHGFI_ADDOVERLAYS|SHGFI_OVERLAYINDEX; +#else + iconSize|SHGFI_SYSICONINDEX; +#endif // Q_OS_WINCE + unsigned long val = SHGetFileInfo((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) { + //using the unique icon index provided by windows save us from duplicate keys + key = dirIconPixmapCacheKey(info.iIcon, iconSize); + QPixmapCache::find(key, pixmap); + if (!pixmap.isNull()) { + QMutexLocker locker(&mx); + dirIconEntryCache.insert(filePath, FakePointer<int>::create(info.iIcon)); + } + } + + if (pixmap.isNull()) { + pixmap = qt_pixmapFromWinHICON(info.hIcon); + if (!pixmap.isNull()) { + if (cacheableDirIcon) { + QMutexLocker locker(&mx); + QPixmapCache::insert(key, pixmap); + dirIconEntryCache.insert(filePath, FakePointer<int>::create(info.iIcon)); + } + } else { + qWarning("QWindowsTheme::fileIconPixmap() no icon found"); + } + } + DestroyIcon(info.hIcon); + } + + if (!pixmap.isNull()) + return pixmap; + return QPlatformTheme::fileIconPixmap(fileInfo, size); +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowstheme.h b/src/plugins/platforms/windows/qwindowstheme.h index 7e885b8f3e..89ef527e76 100644 --- a/src/plugins/platforms/windows/qwindowstheme.h +++ b/src/plugins/platforms/windows/qwindowstheme.h @@ -67,6 +67,9 @@ public: virtual const QFont *font(Font type = SystemFont) const { return m_fonts[type]; } + virtual QPixmap standardPixmap(StandardPixmap sp, const QSizeF &size) const; + virtual QPixmap fileIconPixmap(const QFileInfo &fileInfo, const QSizeF &size) const; + void windowsThemeChanged(QWindow *window); static const char *name; |