|
20 | 20 | import org.eclipse.swt.*;
|
21 | 21 | import org.eclipse.swt.graphics.*;
|
22 | 22 | import org.eclipse.swt.internal.*;
|
| 23 | +import org.eclipse.swt.internal.ole.win32.*; |
23 | 24 | import org.eclipse.swt.internal.win32.*;
|
| 25 | +import org.eclipse.swt.widgets.*; |
24 | 26 |
|
25 | 27 | /**
|
26 | 28 | * Instances of this class represent programs and
|
@@ -381,26 +383,20 @@ public ImageData getImageData () {
|
381 | 383 | public ImageData getImageData (int zoom) {
|
382 | 384 | // OS.SHGetFileInfo is System DPI-aware, hence it retrieves the icon with zoom
|
383 | 385 | // of primary monitor at the application startup
|
384 |
| - int initialNativeZoom = getPrimaryMonitorZoomAtStartup(); |
385 | 386 | if (extension != null) {
|
386 | 387 | 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 |
| - } |
| 388 | + int flags = OS.SHGFI_USEFILEATTRIBUTES | OS.SHGFI_ICONLOCATION; |
395 | 389 | TCHAR pszPath = new TCHAR (0, extension, true);
|
396 | 390 | 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 (); |
| 391 | + if (shfi.iIcon >= 0) { |
| 392 | + Image icon = getImageForZoom(zoom, shfi.iIcon); |
| 393 | + ImageData imageData = icon.getImageData(zoom); |
| 394 | + icon.dispose(); |
401 | 395 | return imageData;
|
402 | 396 | }
|
403 | 397 | }
|
| 398 | + |
| 399 | + int initialNativeZoom = getPrimaryMonitorZoomAtStartup(); |
404 | 400 | int nIconIndex = 0;
|
405 | 401 | String fileName = iconName;
|
406 | 402 | int index = iconName.indexOf (',');
|
@@ -434,6 +430,60 @@ private int getPrimaryMonitorZoomAtStartup() {
|
434 | 430 | return DPIUtil.mapDPIToZoom(dpi);
|
435 | 431 | }
|
436 | 432 |
|
| 433 | +private NavigableMap<Integer, Long> getImageListinAllAvailableSizesMappedWithZoom() { |
| 434 | + TreeMap<Integer, Long> zoomToHImageList = new TreeMap<>(); |
| 435 | + int primaryMonitorZoomAtStartup = getPrimaryMonitorZoomAtStartup(); |
| 436 | + // SHIL_SYSSMALL is the size of icon at startup zoom of the primary monitor. The |
| 437 | + // sizes can differ as specified by OS.GetSystemMetrics. |
| 438 | + long hImageListAtPrimaryMonitorZoomAtStartup = getImageListForSize(OS.SHIL_SYSSMALL); |
| 439 | + int sizeAtPrimaryMonitorZoomAtStartup = getIconSizeOfImageList(hImageListAtPrimaryMonitorZoomAtStartup); |
| 440 | + zoomToHImageList.put(primaryMonitorZoomAtStartup, hImageListAtPrimaryMonitorZoomAtStartup); |
| 441 | + // SHIL_* (SMALL, LARGE and EXTRALARGE) are typically 1x, 2x, 3x relative to the |
| 442 | + // primary monitor zoom at startup, e.g., 16px, 32px and 48px |
| 443 | + // respectively. |
| 444 | + int[] allSizes = new int[] { OS.SHIL_SMALL, OS.SHIL_LARGE, OS.SHIL_EXTRALARGE }; |
| 445 | + for (int size : allSizes) { |
| 446 | + long hImageList = getImageListForSize(size); |
| 447 | + int iconSize = getIconSizeOfImageList(hImageList); |
| 448 | + int zoom = (iconSize / sizeAtPrimaryMonitorZoomAtStartup) * primaryMonitorZoomAtStartup; |
| 449 | + if (!zoomToHImageList.containsKey(zoom)) { |
| 450 | + zoomToHImageList.put(zoom, hImageList); |
| 451 | + } else { |
| 452 | + OS.ImageList_Destroy(hImageList); |
| 453 | + } |
| 454 | + } |
| 455 | + return zoomToHImageList; |
| 456 | +} |
| 457 | + |
| 458 | +private int getIconSizeOfImageList(long hImageList) { |
| 459 | + int [] cx = new int [1]; |
| 460 | + int [] cy = new int [1]; |
| 461 | + OS.ImageList_GetIconSize(hImageList, cx, cy); |
| 462 | + return cx[0]; |
| 463 | +} |
| 464 | + |
| 465 | +private Image getImageForZoom(int zoom, int index) { |
| 466 | + NavigableMap<Integer, Long> zoomToHImageList = getImageListinAllAvailableSizesMappedWithZoom(); |
| 467 | + int closestZoomAvailable = getClosestKey(zoomToHImageList, zoom); |
| 468 | + long hIcon = OS.ImageList_GetIcon(zoomToHImageList.get(closestZoomAvailable), index, OS.ILD_TRANSPARENT); |
| 469 | + zoomToHImageList.values().forEach(handle -> OS.ImageList_Destroy(handle)); |
| 470 | + return Image.win32_new(Display.getCurrent(), SWT.ICON, hIcon, closestZoomAvailable); |
| 471 | +} |
| 472 | + |
| 473 | +private long getImageListForSize(int size) { |
| 474 | + long [] ppv = new long [1]; |
| 475 | + COM.SHGetImageList(size, COM.IID_IImageList, ppv); |
| 476 | + return ppv[0]; |
| 477 | +} |
| 478 | + |
| 479 | +private static int getClosestKey(NavigableMap<Integer, Long> map, int x) { |
| 480 | + Integer floorKey = map.floorKey(x); |
| 481 | + Integer ceilingKey = map.ceilingKey(x); |
| 482 | + if (floorKey == null) return ceilingKey; |
| 483 | + if (ceilingKey == null) return floorKey; |
| 484 | + return (Math.abs(x - floorKey) <= Math.abs(x - ceilingKey)) ? floorKey : ceilingKey; |
| 485 | +} |
| 486 | + |
437 | 487 | /**
|
438 | 488 | * Returns the receiver's name. This is as short and
|
439 | 489 | * descriptive a name as possible for the program. If
|
|
0 commit comments