Skip to content

Commit e3c0392

Browse files
committed
[Win32] Assign cursor handle disposal logic in CursorHandle type
Currently, cursor handles are destroyed in different ways depending on whether the `isIcon` field is set. This field is set in cases when the handle is created for an OS icon handle. This contract has to be ensured implicitly and can easily be broken. With this change, the cursor handle creation creates an according CursorHandle type that is capable of executing the associated disposal logic.
1 parent 86cedfc commit e3c0392

File tree

1 file changed

+68
-43
lines changed
  • bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics

1 file changed

+68
-43
lines changed

bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Cursor.java

Lines changed: 68 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -66,10 +66,9 @@ public final class Cursor extends Resource {
6666
*/
6767
private static final int DEFAULT_ZOOM = 100;
6868

69-
private HashMap<Integer, Long> zoomLevelToHandle = new HashMap<>();
69+
private HashMap<Integer, CursorHandle> zoomLevelToHandle = new HashMap<>();
7070

7171
private final CursorHandleProvider cursorHandleProvider;
72-
boolean isIcon;
7372

7473
/**
7574
* Constructs a new cursor given a device and a style
@@ -120,7 +119,7 @@ public final class Cursor extends Resource {
120119
public Cursor(Device device, int style) {
121120
super(device);
122121
this.cursorHandleProvider = new StyleCursorHandleProvider(style);
123-
this.handle = this.cursorHandleProvider.createHandle(device, DEFAULT_ZOOM);
122+
this.handle = this.cursorHandleProvider.createHandle(device, DEFAULT_ZOOM).getHandle();
124123
init();
125124
this.device.registerResourceWithZoomSupport(this);
126125
}
@@ -161,12 +160,12 @@ public Cursor(Device device, int style) {
161160
public Cursor(Device device, ImageData source, ImageData mask, int hotspotX, int hotspotY) {
162161
super(device);
163162
this.cursorHandleProvider = new ImageDataWithMaskCursorHandleProvider(source, mask, hotspotX, hotspotY);
164-
this.handle = this.cursorHandleProvider.createHandle(device, DEFAULT_ZOOM);
163+
this.handle = this.cursorHandleProvider.createHandle(device, DEFAULT_ZOOM).getHandle();
165164
init();
166165
this.device.registerResourceWithZoomSupport(this);
167166
}
168167

169-
private static long setupCursorFromImageData(ImageData source, ImageData mask, int hotspotX, int hotspotY) {
168+
private static CursorHandle setupCursorFromImageData(ImageData source, ImageData mask, int hotspotX, int hotspotY) {
170169
if (source == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
171170
if (mask == null) {
172171
if (source.getTransparencyType() != SWT.TRANSPARENCY_MASK) {
@@ -195,7 +194,7 @@ private static long setupCursorFromImageData(ImageData source, ImageData mask, i
195194
long hInst = OS.GetModuleHandle(null);
196195
long handle = OS.CreateCursor(hInst, hotspotX, hotspotY, source.width, source.height, sourceData, maskData);
197196
if (handle == 0) SWT.error(SWT.ERROR_NO_HANDLES);
198-
return handle;
197+
return new CustomCursorHandle(handle);
199198
}
200199

201200
/**
@@ -230,13 +229,12 @@ private static long setupCursorFromImageData(ImageData source, ImageData mask, i
230229
public Cursor(Device device, ImageData source, int hotspotX, int hotspotY) {
231230
super(device);
232231
this.cursorHandleProvider = new ImageDataCursorHandleProvider(source, hotspotX, hotspotY);
233-
isIcon = true;
234-
this.handle = this.cursorHandleProvider.createHandle(device, DEFAULT_ZOOM);
232+
this.handle = this.cursorHandleProvider.createHandle(device, DEFAULT_ZOOM).getHandle();
235233
init();
236234
this.device.registerResourceWithZoomSupport(this);
237235
}
238236

239-
private static long setupCursorFromImageData(Device device, ImageData source, int hotspotX, int hotspotY) {
237+
private static CursorHandle setupCursorFromImageData(Device device, ImageData source, int hotspotX, int hotspotY) {
240238
if (source == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
241239
/* Check the hotspots */
242240
if (hotspotX >= source.width || hotspotX < 0 ||
@@ -307,7 +305,7 @@ private static long setupCursorFromImageData(Device device, ImageData source, in
307305
OS.DeleteObject(hMask);
308306
if (handle == 0) SWT.error(SWT.ERROR_NO_HANDLES);
309307

310-
return handle;
308+
return new IconCursorHandle(handle);
311309
}
312310

313311
/**
@@ -343,8 +341,7 @@ public Cursor(Device device, ImageDataProvider imageDataProvider, int hotspotX,
343341
super(device);
344342
if (imageDataProvider == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
345343
this.cursorHandleProvider = new ImageDataProviderCursorHandleProvider(imageDataProvider, hotspotX, hotspotY);
346-
isIcon = true;
347-
this.handle = this.cursorHandleProvider.createHandle(device, DEFAULT_ZOOM);
344+
this.handle = this.cursorHandleProvider.createHandle(device, DEFAULT_ZOOM).getHandle();
348345
init();
349346
this.device.registerResourceWithZoomSupport(this);
350347
}
@@ -369,18 +366,18 @@ public static Long win32_getHandle (Cursor cursor, int zoom) {
369366
return cursor.handle;
370367
}
371368
if (cursor.zoomLevelToHandle.get(zoom) != null) {
372-
return cursor.zoomLevelToHandle.get(zoom);
369+
return cursor.zoomLevelToHandle.get(zoom).getHandle();
373370
}
374371

375-
long handle = cursor.cursorHandleProvider.createHandle(cursor.device, zoom);
372+
CursorHandle handle = cursor.cursorHandleProvider.createHandle(cursor.device, zoom);
376373
cursor.setHandleForZoomLevel(handle, zoom);
377374

378-
return cursor.zoomLevelToHandle.get(zoom);
375+
return cursor.zoomLevelToHandle.get(zoom).getHandle();
379376
}
380377

381-
private void setHandleForZoomLevel(long handle, Integer zoom) {
378+
private void setHandleForZoomLevel(CursorHandle handle, Integer zoom) {
382379
if (this.handle == 0) {
383-
this.handle = handle; // Set handle for default zoom level
380+
this.handle = handle.getHandle(); // Set handle for default zoom level
384381
}
385382
if (zoom != null && !zoomLevelToHandle.containsKey(zoom)) {
386383
zoomLevelToHandle.put(zoom, handle);
@@ -406,29 +403,13 @@ void destroy () {
406403
}
407404

408405
private void destroyHandle () {
409-
for (Long handle : zoomLevelToHandle.values()) {
410-
destroyHandle(handle);
406+
for (CursorHandle handle : zoomLevelToHandle.values()) {
407+
handle.destroy();
411408
}
412409
zoomLevelToHandle.clear();
413410
handle = 0;
414411
}
415412

416-
private void destroyHandle(long handle) {
417-
if (isIcon) {
418-
OS.DestroyIcon(handle);
419-
} else {
420-
/*
421-
* The MSDN states that one should not destroy a shared
422-
* cursor, that is, one obtained from LoadCursor.
423-
* However, it does not appear to do any harm, so rather
424-
* than keep track of how a cursor was created, we just
425-
* destroy them all. If this causes problems in the future,
426-
* put the flag back in.
427-
*/
428-
OS.DestroyCursor(handle);
429-
}
430-
}
431-
432413
/**
433414
* Compares the argument to the receiver, and returns true
434415
* if they represent the <em>same</em> object using a class
@@ -494,15 +475,59 @@ void destroyHandlesExcept(Set<Integer> zoomLevels) {
494475
zoomLevelToHandle.entrySet().removeIf(entry -> {
495476
final Integer zoom = entry.getKey();
496477
if (!zoomLevels.contains(zoom) && zoom != DPIUtil.getZoomForAutoscaleProperty(DEFAULT_ZOOM)) {
497-
destroyHandle(entry.getValue());
478+
entry.getValue().destroy();
498479
return true;
499480
}
500481
return false;
501482
});
502483
}
503484

485+
private static abstract class CursorHandle {
486+
private final long handle;
487+
488+
public CursorHandle(long handle) {
489+
this.handle = handle;
490+
}
491+
492+
long getHandle() {
493+
return handle;
494+
}
495+
496+
abstract void destroy();
497+
}
498+
499+
private static class IconCursorHandle extends CursorHandle {
500+
public IconCursorHandle(long handle) {
501+
super(handle);
502+
}
503+
504+
@Override
505+
void destroy() {
506+
OS.DestroyIcon(getHandle());
507+
}
508+
}
509+
510+
private static class CustomCursorHandle extends CursorHandle {
511+
public CustomCursorHandle(long handle) {
512+
super(handle);
513+
}
514+
515+
@Override
516+
void destroy() {
517+
/*
518+
* The MSDN states that one should not destroy a shared
519+
* cursor, that is, one obtained from LoadCursor.
520+
* However, it does not appear to do any harm, so rather
521+
* than keep track of how a cursor was created, we just
522+
* destroy them all. If this causes problems in the future,
523+
* put the flag back in.
524+
*/
525+
OS.DestroyCursor(getHandle());
526+
}
527+
}
528+
504529
private static interface CursorHandleProvider {
505-
long createHandle(Device device, int zoom);
530+
CursorHandle createHandle(Device device, int zoom);
506531
}
507532

508533
private static class StyleCursorHandleProvider implements CursorHandleProvider {
@@ -513,12 +538,12 @@ public StyleCursorHandleProvider(int style) {
513538
}
514539

515540
@Override
516-
public long createHandle(Device device, int zoom) {
541+
public CursorHandle createHandle(Device device, int zoom) {
517542
// zoom ignored, LoadCursor handles scaling internally
518543
return setupCursorFromStyle(this.style);
519544
}
520545

521-
private static final long setupCursorFromStyle(int style) {
546+
private static final CursorHandle setupCursorFromStyle(int style) {
522547
long lpCursorName = 0;
523548
switch (style) {
524549
case SWT.CURSOR_HAND:
@@ -594,7 +619,7 @@ private static final long setupCursorFromStyle(int style) {
594619
if (handle == 0) {
595620
SWT.error(SWT.ERROR_NO_HANDLES);
596621
}
597-
return handle;
622+
return new CustomCursorHandle(handle);
598623
}
599624
}
600625

@@ -625,7 +650,7 @@ public ImageDataProviderCursorHandleProvider(ImageDataProvider provider, int hot
625650
}
626651

627652
@Override
628-
public long createHandle(Device device, int zoom) {
653+
public CursorHandle createHandle(Device device, int zoom) {
629654
ImageData source;
630655
if (zoom == DEFAULT_ZOOM) {
631656
source = this.provider.getImageData(DEFAULT_ZOOM);
@@ -647,7 +672,7 @@ public ImageDataCursorHandleProvider(ImageData source, int hotspotX, int hotspot
647672
}
648673

649674
@Override
650-
public long createHandle(Device device, int zoom) {
675+
public CursorHandle createHandle(Device device, int zoom) {
651676
ImageData scaledSource = DPIUtil.scaleImageData(device, this.source, zoom, DEFAULT_ZOOM);
652677
return setupCursorFromImageData(device, scaledSource, getHotpotXInPixels(zoom),
653678
getHotpotYInPixels(zoom));
@@ -663,7 +688,7 @@ public ImageDataWithMaskCursorHandleProvider(ImageData source, ImageData mask, i
663688
}
664689

665690
@Override
666-
public long createHandle(Device device, int zoom) {
691+
public CursorHandle createHandle(Device device, int zoom) {
667692
ImageData scaledSource = DPIUtil.scaleImageData(device, this.source, zoom, DEFAULT_ZOOM);
668693
ImageData scaledMask = this.mask != null ? DPIUtil.scaleImageData(device, mask, zoom, DEFAULT_ZOOM)
669694
: null;

0 commit comments

Comments
 (0)