Draw icon overlay manually instead of relying on the api

Even with SHGSI_LINKOVERLAY flag set, loaded Icon with
SHDefExtractIcon doesn't have any overlay, so we draw
it manually.

Pick-to: 6.9 6.8
Fixes: QTBUG-131843
Change-Id: Iae4c2da12104a361b9a8cf05c78adcdb698f1f82
Reviewed-by: Christian Ehrlicher <ch.ehrlicher@gmx.de>
This commit is contained in:
Morteza Jamshidi 2024-12-10 12:32:08 +01:00
parent 8f2f4ad468
commit fd7bc16e9f

View File

@ -822,7 +822,6 @@ QPixmap QWindowsTheme::standardPixmap(StandardPixmap sp, const QSizeF &pixmapSiz
{ {
int resourceId = -1; int resourceId = -1;
SHSTOCKICONID stockId = SIID_INVALID; SHSTOCKICONID stockId = SIID_INVALID;
UINT stockFlags = 0;
LPCTSTR iconName = nullptr; LPCTSTR iconName = nullptr;
switch (sp) { switch (sp) {
case DriveCDIcon: case DriveCDIcon:
@ -846,14 +845,12 @@ QPixmap QWindowsTheme::standardPixmap(StandardPixmap sp, const QSizeF &pixmapSiz
resourceId = 7; resourceId = 7;
break; break;
case FileLinkIcon: case FileLinkIcon:
stockFlags = SHGSI_LINKOVERLAY;
Q_FALLTHROUGH(); Q_FALLTHROUGH();
case FileIcon: case FileIcon:
stockId = SIID_DOCNOASSOC; stockId = SIID_DOCNOASSOC;
resourceId = 1; resourceId = 1;
break; break;
case DirLinkIcon: case DirLinkIcon:
stockFlags = SHGSI_LINKOVERLAY;
Q_FALLTHROUGH(); Q_FALLTHROUGH();
case DirClosedIcon: case DirClosedIcon:
case DirIcon: case DirIcon:
@ -867,7 +864,6 @@ QPixmap QWindowsTheme::standardPixmap(StandardPixmap sp, const QSizeF &pixmapSiz
resourceId = 16; resourceId = 16;
break; break;
case DirLinkOpenIcon: case DirLinkOpenIcon:
stockFlags = SHGSI_LINKOVERLAY;
Q_FALLTHROUGH(); Q_FALLTHROUGH();
case DirOpenIcon: case DirOpenIcon:
stockId = SIID_FOLDEROPEN; stockId = SIID_FOLDEROPEN;
@ -907,16 +903,34 @@ QPixmap QWindowsTheme::standardPixmap(StandardPixmap sp, const QSizeF &pixmapSiz
break; break;
} }
// Even with SHGSI_LINKOVERLAY flag set, loaded Icon with SHDefExtractIcon doesn't have
// any overlay, so we avoid SHGSI_LINKOVERLAY flag and draw it manually (QTBUG-131843)
const auto drawLinkOverlayIcon = [](StandardPixmap sp, QPixmap &pixmap, QSizeF pixmapSize) {
if (sp == FileLinkIcon || sp == DirLinkIcon || sp == DirLinkOpenIcon) {
QPainter painter(&pixmap);
const QSizeF linkSize = pixmapSize / (pixmapSize.height() >= 48 ? 3 : 2);
const QPixmap link = loadIconFromShell32(16769, linkSize.toSize()); // 16769 = LinkOverlayIcon
const int yPos = pixmap.height() - link.size().height();
painter.drawPixmap(0, yPos, int(linkSize.width()), int(linkSize.height()), link);
}
};
const auto dpr = qGuiApp->devicePixelRatio(); // Highest in the system
if (stockId != SIID_INVALID) { if (stockId != SIID_INVALID) {
SHSTOCKICONINFO iconInfo; SHSTOCKICONINFO iconInfo;
memset(&iconInfo, 0, sizeof(iconInfo)); memset(&iconInfo, 0, sizeof(iconInfo));
iconInfo.cbSize = sizeof(iconInfo); iconInfo.cbSize = sizeof(iconInfo);
stockFlags |= SHGSI_ICONLOCATION; constexpr UINT stockFlags = SHGSI_ICONLOCATION;
if (SHGetStockIconInfo(stockId, stockFlags, &iconInfo) == S_OK) { if (SHGetStockIconInfo(stockId, stockFlags, &iconInfo) == S_OK) {
const auto iconSize = pixmapSize.width(); const auto iconSize = pixmapSize.width();
HICON icon; HICON icon;
if (SHDefExtractIcon(iconInfo.szPath, iconInfo.iIcon, 0, &icon, nullptr, iconSize) == S_OK) { if (SHDefExtractIcon(iconInfo.szPath, iconInfo.iIcon, 0, &icon, nullptr, iconSize) == S_OK) {
QPixmap pixmap = qt_pixmapFromWinHICON(icon); QPixmap pixmap = qt_pixmapFromWinHICON(icon);
if (!pixmap.isNull()) {
drawLinkOverlayIcon(sp, pixmap, pixmap.size());
pixmap.setDevicePixelRatio(dpr);
}
DestroyIcon(icon); DestroyIcon(icon);
return pixmap; return pixmap;
} }
@ -926,11 +940,8 @@ QPixmap QWindowsTheme::standardPixmap(StandardPixmap sp, const QSizeF &pixmapSiz
if (resourceId != -1) { if (resourceId != -1) {
QPixmap pixmap = loadIconFromShell32(resourceId, pixmapSize); QPixmap pixmap = loadIconFromShell32(resourceId, pixmapSize);
if (!pixmap.isNull()) { if (!pixmap.isNull()) {
if (sp == FileLinkIcon || sp == DirLinkIcon || sp == DirLinkOpenIcon) { drawLinkOverlayIcon(sp, pixmap, pixmapSize);
QPainter painter(&pixmap); pixmap.setDevicePixelRatio(dpr);
QPixmap link = loadIconFromShell32(30, pixmapSize);
painter.drawPixmap(0, 0, int(pixmapSize.width()), int(pixmapSize.height()), link);
}
return pixmap; return pixmap;
} }
} }