From b1ddf05baacb5b80a1935685b277abcb25d0b7ce Mon Sep 17 00:00:00 2001 From: Heiko Klare Date: Tue, 30 Jan 2024 12:32:10 +0100 Subject: [PATCH] Use large program icons on Windows Icons for files associated with an external program area always loaded in small size using the Windows API. The API also provides an option to load large icons, which have twice the size of the small ones. In order to improve the icon sharpness when retrieving the icon for (monitor) scale value of more than 100%, this change ensures that the higher resolution icon is used and scaled appropriately. --- .../org/eclipse/swt/internal/win32/OS.java | 1 + .../org/eclipse/swt/program/Program.java | 63 ++++++++++++++----- 2 files changed, 50 insertions(+), 14 deletions(-) diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/win32/org/eclipse/swt/internal/win32/OS.java b/bundles/org.eclipse.swt/Eclipse SWT PI/win32/org/eclipse/swt/internal/win32/OS.java index c3cfd904f28..7fd6d49f013 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT PI/win32/org/eclipse/swt/internal/win32/OS.java +++ b/bundles/org.eclipse.swt/Eclipse SWT PI/win32/org/eclipse/swt/internal/win32/OS.java @@ -1196,6 +1196,7 @@ public class OS extends C { public static final int SET_FEATURE_ON_PROCESS = 0x2; public static final int SHADEBLENDCAPS = 120; public static final int SHGFI_ICON = 0x000000100; + public static final int SHGFI_LARGEICON= 0x0; public static final int SHGFI_SMALLICON= 0x1; public static final int SHGFI_USEFILEATTRIBUTES = 0x000000010; public static final int SIGDN_FILESYSPATH = 0x80058000; diff --git a/bundles/org.eclipse.swt/Eclipse SWT Program/win32/org/eclipse/swt/program/Program.java b/bundles/org.eclipse.swt/Eclipse SWT Program/win32/org/eclipse/swt/program/Program.java index a5d483c30fb..a0aeef36ea8 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT Program/win32/org/eclipse/swt/program/Program.java +++ b/bundles/org.eclipse.swt/Eclipse SWT Program/win32/org/eclipse/swt/program/Program.java @@ -20,6 +20,7 @@ import org.eclipse.swt.*; import org.eclipse.swt.graphics.*; import org.eclipse.swt.internal.*; +import org.eclipse.swt.internal.DPIUtil.*; import org.eclipse.swt.internal.win32.*; import org.eclipse.swt.widgets.*; @@ -382,20 +383,50 @@ public ImageData getImageData () { public ImageData getImageData (int zoom) { // Windows API returns image data according to primary monitor zoom factor // rather than at original scaling - int nativeZoomFactor = 100 * Display.getCurrent().getPrimaryMonitor().getZoom() / DPIUtil.getDeviceZoom(); + int primaryMonitorZoom = Display.getCurrent().getPrimaryMonitor().getZoom(); + int nativeZoomFactor = 100 * primaryMonitorZoom / DPIUtil.getDeviceZoom(); int imageZoomFactor = 100 * zoom / nativeZoomFactor; + // Use small icon if expected icon size is less than 150% of delivered icon size + // and use large icon if it is more than 150% of the delivered icon size + boolean useLargeIcon = 100 * zoom / primaryMonitorZoom > 200; + ElementAtZoom zoomedIcon = null; if (extension != null) { - SHFILEINFO shfi = new SHFILEINFO (); - int flags = OS.SHGFI_ICON | OS.SHGFI_SMALLICON | OS.SHGFI_USEFILEATTRIBUTES; - TCHAR pszPath = new TCHAR (0, extension, true); - OS.SHGetFileInfo (pszPath.chars, OS.FILE_ATTRIBUTE_NORMAL, shfi, SHFILEINFO.sizeof, flags); + zoomedIcon = loadIconForFileExtension(useLargeIcon); + } + if (zoomedIcon == null) { + zoomedIcon = loadIconForFile(useLargeIcon); + } + if (zoomedIcon != null) { + Image image = zoomedIcon.element(); + ImageData imageData = image.getImageData (imageZoomFactor * 100 / zoomedIcon.zoom()); + image.dispose (); + return imageData; + } + return null; +} + +private ElementAtZoom loadIconForFileExtension(boolean useLargeIconIfAvailable) { + SHFILEINFO shfi = new SHFILEINFO (); + TCHAR pszPath = new TCHAR (0, extension, true); + int flags = OS.SHGFI_ICON | OS.SHGFI_USEFILEATTRIBUTES; + int iconZoom = 100; + if (useLargeIconIfAvailable) { + OS.SHGetFileInfo (pszPath.chars, OS.FILE_ATTRIBUTE_NORMAL, shfi, SHFILEINFO.sizeof, flags | OS.SHGFI_LARGEICON); if (shfi.hIcon != 0) { - Image image = Image.win32_new (null, SWT.ICON, shfi.hIcon); - ImageData imageData = image.getImageData (imageZoomFactor); - image.dispose (); - return imageData; + iconZoom = 200; } } + if (shfi.hIcon == 0) { + OS.SHGetFileInfo (pszPath.chars, OS.FILE_ATTRIBUTE_NORMAL, shfi, SHFILEINFO.sizeof, flags | OS.SHGFI_SMALLICON); + } + if (shfi.hIcon != 0) { + Image image = Image.win32_new (null, SWT.ICON, shfi.hIcon); + return new ElementAtZoom<>(image, iconZoom); + } + return null; +} + +private ElementAtZoom loadIconForFile(boolean useLargeIconIfAvailable) { int nIconIndex = 0; String fileName = iconName; int index = iconName.indexOf (','); @@ -414,12 +445,16 @@ public ImageData getImageData (int zoom) { } TCHAR lpszFile = new TCHAR (0, fileName, true); long [] phiconSmall = new long[1], phiconLarge = null; + if (useLargeIconIfAvailable) { + phiconLarge = new long[1]; + } OS.ExtractIconEx (lpszFile, nIconIndex, phiconLarge, phiconSmall, 1); - if (phiconSmall [0] == 0) return null; - Image image = Image.win32_new (null, SWT.ICON, phiconSmall [0]); - ImageData imageData = image.getImageData (imageZoomFactor); - image.dispose (); - return imageData; + if (useLargeIconIfAvailable && phiconLarge[0] != 0) { + return new ElementAtZoom<>(Image.win32_new (null, SWT.ICON, phiconLarge[0]), 200); + } else if (phiconSmall[0] != 0) { + return new ElementAtZoom<>(Image.win32_new (null, SWT.ICON, phiconSmall[0]), 100); + } + return null; } /**