Skip to content

Commit 4308424

Browse files
Refactor Cursor handle to support per-zoom handles
- Removed the dedicated `handle` field from Cursor; all native handles are now stored in `zoomLevelToHandle`. - Ensured the default zoom level (100) handle is always created during cursor construction. - Updated hashCode, equals, isDisposed, and destroy to work with zoom-level handles. - Prevents resource leaks caused by undisposed temporary cursors and supports safe, reusable handle management across zoom levels. fixes #2355
1 parent 7f19dc5 commit 4308424

File tree

1 file changed

+30
-36
lines changed
  • bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics

1 file changed

+30
-36
lines changed

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

Lines changed: 30 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -49,18 +49,6 @@
4949
*/
5050
public final class Cursor extends Resource {
5151

52-
/**
53-
* the handle to the OS cursor resource
54-
* (Warning: This field is platform dependent)
55-
* <p>
56-
* <b>IMPORTANT:</b> This field is <em>not</em> part of the SWT
57-
* public API. It is marked public only so that it can be shared
58-
* within the packages provided by SWT. It is not available on all
59-
* platforms and should never be accessed from application code.
60-
* </p>
61-
*
62-
*/
63-
private long handle;
6452
/**
6553
* Attribute to cache current native zoom level
6654
*/
@@ -74,6 +62,8 @@ public final class Cursor extends Resource {
7462
private final ImageData mask;
7563
private final int hotspotX;
7664
private final int hotspotY;
65+
private boolean isDestroyed;
66+
private Integer style;
7767
/**
7868
* Prevents uninitialized instances from being created outside the package.
7969
*/
@@ -135,7 +125,9 @@ public final class Cursor extends Resource {
135125
*/
136126
public Cursor(Device device, int style) {
137127
this(device);
138-
this.handle = setupCursorFromStyle(style);
128+
this.style = style;
129+
long handle = setupCursorFromStyle(style);
130+
zoomLevelToHandle.put(DEFAULT_ZOOM, handle);
139131
init();
140132
}
141133

@@ -212,7 +204,8 @@ public Cursor(Device device, ImageData source, ImageData mask, int hotspotX, int
212204
this.hotspotX = hotspotX;
213205
this.hotspotY = hotspotY;
214206
this.imageDataProvider = null;
215-
this.handle = setupCursorFromImageData(source, mask, hotspotX, hotspotY);
207+
long handle = setupCursorFromImageData(source, mask, hotspotX, hotspotY);
208+
zoomLevelToHandle.put(DEFAULT_ZOOM, handle);
216209
init();
217210
this.device.registerResourceWithZoomSupport(this);
218211
}
@@ -285,8 +278,9 @@ public Cursor(Device device, ImageData source, int hotspotX, int hotspotY) {
285278
this.hotspotX = hotspotX;
286279
this.hotspotY = hotspotY;
287280
this.imageDataProvider = null;
288-
this.handle = setupCursorFromImageData(device, source, hotspotX, hotspotY);
281+
long handle = setupCursorFromImageData(device, source, hotspotX, hotspotY);
289282
isIcon = true;
283+
zoomLevelToHandle.put(DEFAULT_ZOOM, handle);
290284
init();
291285
this.device.registerResourceWithZoomSupport(this);
292286
}
@@ -402,8 +396,9 @@ public Cursor(Device device, ImageDataProvider imageDataProvider, int hotspotX,
402396
this.mask = null;
403397
this.hotspotX = hotspotX;
404398
this.hotspotY = hotspotY;
405-
this.handle = setupCursorFromImageData(device, this.source, hotspotX, hotspotY);
399+
long handle = setupCursorFromImageData(device, this.source, hotspotX, hotspotY);
406400
isIcon = true;
401+
zoomLevelToHandle.put(DEFAULT_ZOOM, handle);
407402
init();
408403
this.device.registerResourceWithZoomSupport(this);
409404
}
@@ -424,41 +419,40 @@ public Cursor(Device device, ImageDataProvider imageDataProvider, int hotspotX,
424419
* @noreference This method is not intended to be referenced by clients.
425420
*/
426421
public static Long win32_getHandle (Cursor cursor, int zoom) {
427-
if (cursor.isDisposed()) {
428-
return cursor.handle;
422+
if(cursor.zoomLevelToHandle.size() == 0) {
423+
return 0L;
429424
}
430425
if (cursor.zoomLevelToHandle.get(zoom) != null) {
431426
return cursor.zoomLevelToHandle.get(zoom);
432427
}
433428

434-
if (cursor.source == null) {
435-
cursor.setHandleForZoomLevel(cursor.handle, zoom);
429+
if (cursor.style != null) {
430+
// we don't need to pass zoom in this case. LoadCursor will always return scaled cursor even though handle value will be same for all zoom levels.
431+
long handle = setupCursorFromStyle(cursor.style);
432+
cursor.setHandleForZoomLevel(handle, zoom);
436433
} else {
437434
ImageData source;
438435
if (cursor.imageDataProvider != null) {
439436
Image tempImage = new Image(cursor.getDevice(), cursor.imageDataProvider);
440437
source = tempImage.getImageData(zoom);
441438
tempImage.dispose();
439+
} else {
440+
source = DPIUtil.scaleImageData(cursor.getDevice(), cursor.source, zoom, DEFAULT_ZOOM);
442441
}
443-
else {
444-
source = DPIUtil.scaleImageData(cursor.device, cursor.source, zoom, DEFAULT_ZOOM);
445-
}
442+
446443
if (cursor.isIcon) {
447-
Cursor newCursor = new Cursor(cursor.device, source, Win32DPIUtils.pointToPixel(cursor.hotspotX, zoom), Win32DPIUtils.pointToPixel(cursor.hotspotY, zoom));
448-
cursor.setHandleForZoomLevel(newCursor.handle, zoom);
444+
long handle = setupCursorFromImageData(cursor.getDevice(), source, Win32DPIUtils.pointToPixel(cursor.hotspotX, zoom), Win32DPIUtils.pointToPixel(cursor.hotspotY, zoom));
445+
cursor.setHandleForZoomLevel(handle, zoom);
449446
} else {
450-
ImageData mask = DPIUtil.scaleImageData(cursor.device, cursor.mask, zoom, DEFAULT_ZOOM);
451-
Cursor newCursor = new Cursor(cursor.device, source, mask, Win32DPIUtils.pointToPixel(cursor.hotspotX, zoom), Win32DPIUtils.pointToPixel(cursor.hotspotY, zoom));
452-
cursor.setHandleForZoomLevel(newCursor.handle, zoom);
447+
ImageData mask = DPIUtil.scaleImageData(cursor.getDevice(), cursor.mask, zoom, DEFAULT_ZOOM);
448+
long handle = setupCursorFromImageData(source, mask, Win32DPIUtils.pointToPixel(cursor.hotspotX, zoom), Win32DPIUtils.pointToPixel(cursor.hotspotY, zoom));
449+
cursor.setHandleForZoomLevel(handle, zoom);
453450
}
454451
}
455452
return cursor.zoomLevelToHandle.get(zoom);
456453
}
457454

458455
private void setHandleForZoomLevel(long handle, Integer zoom) {
459-
if (this.handle == 0) {
460-
this.handle = handle; // Set handle for default zoom level
461-
}
462456
if (zoom != null && !zoomLevelToHandle.containsKey(zoom)) {
463457
zoomLevelToHandle.put(zoom, handle);
464458
}
@@ -480,14 +474,14 @@ void destroy () {
480474
// }
481475
device.deregisterResourceWithZoomSupport(this);
482476
destroyHandle();
477+
this.isDestroyed = true;
483478
}
484479

485480
private void destroyHandle () {
486481
for (Long handle : zoomLevelToHandle.values()) {
487482
destroyHandle(handle);
488483
}
489484
zoomLevelToHandle.clear();
490-
handle = 0;
491485
}
492486

493487
private void destroyHandle(long handle) {
@@ -521,7 +515,7 @@ public boolean equals (Object object) {
521515
if (object == this) return true;
522516
if (!(object instanceof Cursor)) return false;
523517
Cursor cursor = (Cursor) object;
524-
return device == cursor.device && handle == cursor.handle;
518+
return device == cursor.device && win32_getHandle(this, DEFAULT_ZOOM) == win32_getHandle(cursor, DEFAULT_ZOOM);
525519
}
526520

527521
/**
@@ -536,7 +530,7 @@ public boolean equals (Object object) {
536530
*/
537531
@Override
538532
public int hashCode () {
539-
return (int)handle;
533+
return this.zoomLevelToHandle.get(DEFAULT_ZOOM) != null? this.zoomLevelToHandle.get(DEFAULT_ZOOM).intValue() : 0;
540534
}
541535

542536
/**
@@ -551,7 +545,7 @@ public int hashCode () {
551545
*/
552546
@Override
553547
public boolean isDisposed() {
554-
return handle == 0;
548+
return isDestroyed;
555549
}
556550

557551
/**
@@ -563,7 +557,7 @@ public boolean isDisposed() {
563557
@Override
564558
public String toString () {
565559
if (isDisposed()) return "Cursor {*DISPOSED*}";
566-
return "Cursor {" + handle + "}";
560+
return "Cursor {" + zoomLevelToHandle + "}";
567561
}
568562

569563
@Override

0 commit comments

Comments
 (0)