Skip to content

Commit dba3c50

Browse files
committed
Improve Program icons scaling for win32 #62
This commit implements scaling of program icons by retrieving it from SHDefExtractIcon, which also provides the system default icons for the file type followed by a fallback if the pszFile for the icon is not valid. The fallback uses the extension to retrieve the icon using SHGetFileInfo in small and large size and scales it accordingly with the required zoom level. contributes to #62 and #127
1 parent 857ac0b commit dba3c50

File tree

6 files changed

+74
-28
lines changed

6 files changed

+74
-28
lines changed

bundles/org.eclipse.swt/Eclipse SWT PI/win32/library/os.c

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7498,6 +7498,28 @@ JNIEXPORT jint JNICALL OS_NATIVE(SHDRAGIMAGE_1sizeof)
74987498
}
74997499
#endif
75007500

7501+
#ifndef NO_SHDefExtractIcon
7502+
JNIEXPORT jint JNICALL OS_NATIVE(SHDefExtractIcon)
7503+
(JNIEnv *env, jclass that, jcharArray arg0, jint arg1, jint arg2, jlongArray arg3, jlongArray arg4, jint arg5)
7504+
{
7505+
jchar *lparg0=NULL;
7506+
jlong *lparg3=NULL;
7507+
jlong *lparg4=NULL;
7508+
jint rc = 0;
7509+
OS_NATIVE_ENTER(env, that, SHDefExtractIcon_FUNC);
7510+
if (arg0) if ((lparg0 = (*env)->GetCharArrayElements(env, arg0, NULL)) == NULL) goto fail;
7511+
if (arg3) if ((lparg3 = (*env)->GetLongArrayElements(env, arg3, NULL)) == NULL) goto fail;
7512+
if (arg4) if ((lparg4 = (*env)->GetLongArrayElements(env, arg4, NULL)) == NULL) goto fail;
7513+
rc = (jint)SHDefExtractIcon((LPWSTR)lparg0, arg1, arg2, (HICON FAR *)lparg3, (HICON FAR *)lparg4, arg5);
7514+
fail:
7515+
if (arg4 && lparg4) (*env)->ReleaseLongArrayElements(env, arg4, lparg4, 0);
7516+
if (arg3 && lparg3) (*env)->ReleaseLongArrayElements(env, arg3, lparg3, 0);
7517+
if (arg0 && lparg0) (*env)->ReleaseCharArrayElements(env, arg0, lparg0, 0);
7518+
OS_NATIVE_EXIT(env, that, SHDefExtractIcon_FUNC);
7519+
return rc;
7520+
}
7521+
#endif
7522+
75017523
#ifndef NO_SHELLEXECUTEINFO_1sizeof
75027524
JNIEXPORT jint JNICALL OS_NATIVE(SHELLEXECUTEINFO_1sizeof)
75037525
(JNIEnv *env, jclass that)

bundles/org.eclipse.swt/Eclipse SWT PI/win32/library/os_stats.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -567,6 +567,7 @@ typedef enum {
567567
SCROLLBARINFO_1sizeof_FUNC,
568568
SCROLLINFO_1sizeof_FUNC,
569569
SHDRAGIMAGE_1sizeof_FUNC,
570+
SHDefExtractIcon_FUNC,
570571
SHELLEXECUTEINFO_1sizeof_FUNC,
571572
SHFILEINFO_1sizeof_FUNC,
572573
SHGetFileInfo_FUNC,

bundles/org.eclipse.swt/Eclipse SWT PI/win32/library/os_structs.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*******************************************************************************
2-
* Copyright (c) 2000, 2022 IBM Corporation and others.
2+
* Copyright (c) 2000, 2025 IBM Corporation and others.
33
*
44
* This program and the accompanying materials
55
* are made available under the terms of the Eclipse Public License 2.0

bundles/org.eclipse.swt/Eclipse SWT PI/win32/library/os_structs.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*******************************************************************************
2-
* Copyright (c) 2000, 2021 IBM Corporation and others.
2+
* Copyright (c) 2000, 2025 IBM Corporation and others.
33
*
44
* This program and the accompanying materials
55
* are made available under the terms of the Eclipse Public License 2.0

bundles/org.eclipse.swt/Eclipse SWT PI/win32/org/eclipse/swt/internal/win32/OS.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2300,6 +2300,11 @@ public static final boolean SetWindowText (long hWnd, TCHAR lpString) {
23002300
return SetWindowText (hWnd, lpString1);
23012301
}
23022302

2303+
public static final int SHDefExtractIcon (TCHAR lpszFile, int iIndex, int uFlags, long [] phiconLarge, long [] phiconSmall, int nIconSize) {
2304+
char [] lpszFile1 = lpszFile == null ? null : lpszFile.chars;
2305+
return SHDefExtractIcon (lpszFile1, iIndex, uFlags, phiconLarge, phiconSmall, nIconSize);
2306+
}
2307+
23032308
public static final boolean UnregisterClass (TCHAR lpClassName, long hInstance) {
23042309
char [] lpClassName1 = lpClassName == null ? null : lpClassName.chars;
23052310
return UnregisterClass (lpClassName1, hInstance);
@@ -4445,6 +4450,12 @@ public static int HRESULT_FROM_WIN32(int x) {
44454450
* @param lpXform cast=(XFORM *),flags=no_out
44464451
*/
44474452
public static final native boolean SetWorldTransform(long hdc, float[] lpXform);
4453+
/**
4454+
* @param lpszFile cast=(LPWSTR)
4455+
* @param phiconLarge cast=(HICON FAR *)
4456+
* @param phiconSmall cast=(HICON FAR *)
4457+
*/
4458+
public static final native int SHDefExtractIcon (char [] lpszFile, int iIndex, int uFlags, long [] phiconLarge, long [] phiconSmall, int nIconSize);
44484459
/** @param pszPath cast=(LPCWSTR),flags=no_out */
44494460
public static final native long SHGetFileInfo (char [] pszPath, int dwFileAttributes, SHFILEINFO psfi, int cbFileInfo, int uFlags);
44504461
public static final native boolean ShellExecuteEx (SHELLEXECUTEINFO lpExecInfo);

bundles/org.eclipse.swt/Eclipse SWT Program/win32/org/eclipse/swt/program/Program.java

Lines changed: 38 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -379,28 +379,11 @@ public ImageData getImageData () {
379379
* @since 3.125
380380
*/
381381
public ImageData getImageData (int zoom) {
382-
// OS.SHGetFileInfo is System DPI-aware, hence it retrieves the icon with zoom
383-
// of primary monitor at the application startup
384-
int initialNativeZoom = getPrimaryMonitorZoomAtStartup();
385-
if (extension != null) {
386-
SHFILEINFO shfi = new SHFILEINFO ();
387-
int flags = OS.SHGFI_ICON | OS.SHGFI_USEFILEATTRIBUTES;
388-
boolean useLargeIcon = 100 * zoom / initialNativeZoom >= 200;
389-
if(useLargeIcon) {
390-
flags |= OS.SHGFI_LARGEICON;
391-
initialNativeZoom *= 2;
392-
} else {
393-
flags |= OS.SHGFI_SMALLICON;
394-
}
395-
TCHAR pszPath = new TCHAR (0, extension, true);
396-
OS.SHGetFileInfo (pszPath.chars, OS.FILE_ATTRIBUTE_NORMAL, shfi, SHFILEINFO.sizeof, flags);
397-
if (shfi.hIcon != 0) {
398-
Image image = Image.win32_new (null, SWT.ICON, shfi.hIcon, initialNativeZoom);
399-
ImageData imageData = image.getImageData (zoom);
400-
image.dispose ();
401-
return imageData;
402-
}
403-
}
382+
ImageData imageData = getImageDataUsingIconFilePath(zoom);
383+
return (imageData != null) ? imageData : getImageDataUsingExtension(zoom);
384+
}
385+
386+
private ImageData getImageDataUsingIconFilePath(int zoom) {
404387
int nIconIndex = 0;
405388
String fileName = iconName;
406389
int index = iconName.indexOf (',');
@@ -418,15 +401,44 @@ public ImageData getImageData (int zoom) {
418401
}
419402
}
420403
TCHAR lpszFile = new TCHAR (0, fileName, true);
421-
long [] phiconSmall = new long[1], phiconLarge = null;
422-
OS.ExtractIconEx (lpszFile, nIconIndex, phiconLarge, phiconSmall, 1);
423-
if (phiconSmall [0] == 0) return null;
424-
Image image = Image.win32_new (null, SWT.ICON, phiconSmall [0], initialNativeZoom);
404+
long [] hIcon = new long[1];
405+
int size = OS.GetSystemMetricsForDpi(OS.SM_CXSMICON, DPIUtil.mapZoomToDPI(zoom));
406+
OS.SHDefExtractIcon (lpszFile, nIconIndex, 0, hIcon, null, size);
407+
if (hIcon [0] == 0) {
408+
return null;
409+
}
410+
Image image = Image.win32_new (null, SWT.ICON, hIcon [0], zoom);
425411
ImageData imageData = image.getImageData (zoom);
426412
image.dispose ();
427413
return imageData;
428414
}
429415

416+
private ImageData getImageDataUsingExtension(int zoom) {
417+
if (extension != null) {
418+
// OS.SHGetFileInfo is System DPI-aware, hence it retrieves the icon with zoom
419+
// of primary monitor at the application startup
420+
int initialNativeZoom = getPrimaryMonitorZoomAtStartup();
421+
SHFILEINFO shfi = new SHFILEINFO ();
422+
int flags = OS.SHGFI_ICON | OS.SHGFI_USEFILEATTRIBUTES;
423+
boolean useLargeIcon = 100 * zoom / initialNativeZoom >= 200;
424+
if(useLargeIcon) {
425+
flags |= OS.SHGFI_LARGEICON;
426+
initialNativeZoom *= 2;
427+
} else {
428+
flags |= OS.SHGFI_SMALLICON;
429+
}
430+
TCHAR pszPath = new TCHAR (0, extension, true);
431+
OS.SHGetFileInfo (pszPath.chars, OS.FILE_ATTRIBUTE_NORMAL, shfi, SHFILEINFO.sizeof, flags);
432+
if (shfi.hIcon != 0) {
433+
Image image = Image.win32_new (null, SWT.ICON, shfi.hIcon, initialNativeZoom);
434+
ImageData imageData = image.getImageData (zoom);
435+
image.dispose ();
436+
return imageData;
437+
}
438+
}
439+
return null;
440+
}
441+
430442
private int getPrimaryMonitorZoomAtStartup() {
431443
long hDC = OS.GetDC(0);
432444
int dpi = OS.GetDeviceCaps(hDC, OS.LOGPIXELSX);

0 commit comments

Comments
 (0)