Skip to content

Commit da22b08

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`. - Updated hashCode, equals, isDisposed, and destroy to work with zoom-level handles.
1 parent d4c3036 commit da22b08

File tree

2 files changed

+103
-34
lines changed

2 files changed

+103
-34
lines changed

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

Lines changed: 40 additions & 34 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
*/
@@ -70,6 +58,8 @@ public final class Cursor extends Resource {
7058

7159
private final CursorHandleProvider cursorHandleProvider;
7260

61+
private boolean isDestroyed;
62+
7363
/**
7464
* Constructs a new cursor given a device and a style
7565
* constant describing the desired cursor appearance.
@@ -119,7 +109,6 @@ public final class Cursor extends Resource {
119109
public Cursor(Device device, int style) {
120110
super(device);
121111
this.cursorHandleProvider = new StyleCursorHandleProvider(style);
122-
this.handle = this.cursorHandleProvider.createHandle(device, DEFAULT_ZOOM).getHandle();
123112
init();
124113
this.device.registerResourceWithZoomSupport(this);
125114
}
@@ -160,7 +149,6 @@ public Cursor(Device device, int style) {
160149
public Cursor(Device device, ImageData source, ImageData mask, int hotspotX, int hotspotY) {
161150
super(device);
162151
this.cursorHandleProvider = new ImageDataWithMaskCursorHandleProvider(source, mask, hotspotX, hotspotY);
163-
this.handle = this.cursorHandleProvider.createHandle(device, DEFAULT_ZOOM).getHandle();
164152
init();
165153
this.device.registerResourceWithZoomSupport(this);
166154
}
@@ -229,7 +217,6 @@ private static CursorHandle setupCursorFromImageData(ImageData source, ImageData
229217
public Cursor(Device device, ImageData source, int hotspotX, int hotspotY) {
230218
super(device);
231219
this.cursorHandleProvider = new ImageDataCursorHandleProvider(source, hotspotX, hotspotY);
232-
this.handle = this.cursorHandleProvider.createHandle(device, DEFAULT_ZOOM).getHandle();
233220
init();
234221
this.device.registerResourceWithZoomSupport(this);
235222
}
@@ -341,7 +328,6 @@ public Cursor(Device device, ImageDataProvider imageDataProvider, int hotspotX,
341328
super(device);
342329
if (imageDataProvider == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
343330
this.cursorHandleProvider = new ImageDataProviderCursorHandleProvider(imageDataProvider, hotspotX, hotspotY);
344-
this.handle = this.cursorHandleProvider.createHandle(device, DEFAULT_ZOOM).getHandle();
345331
init();
346332
this.device.registerResourceWithZoomSupport(this);
347333
}
@@ -363,7 +349,7 @@ public Cursor(Device device, ImageDataProvider imageDataProvider, int hotspotX,
363349
*/
364350
public static Long win32_getHandle (Cursor cursor, int zoom) {
365351
if (cursor.isDisposed()) {
366-
return cursor.handle;
352+
return 0L;
367353
}
368354
if (cursor.zoomLevelToHandle.get(zoom) != null) {
369355
return cursor.zoomLevelToHandle.get(zoom).getHandle();
@@ -376,9 +362,6 @@ public static Long win32_getHandle (Cursor cursor, int zoom) {
376362
}
377363

378364
private void setHandleForZoomLevel(CursorHandle handle, Integer zoom) {
379-
if (this.handle == 0) {
380-
this.handle = handle.getHandle(); // Set handle for default zoom level
381-
}
382365
if (zoom != null && !zoomLevelToHandle.containsKey(zoom)) {
383366
zoomLevelToHandle.put(zoom, handle);
384367
}
@@ -407,7 +390,7 @@ private void destroyHandle () {
407390
handle.destroy();
408391
}
409392
zoomLevelToHandle.clear();
410-
handle = 0;
393+
this.isDestroyed = true;
411394
}
412395

413396
/**
@@ -425,7 +408,7 @@ public boolean equals (Object object) {
425408
if (object == this) return true;
426409
if (!(object instanceof Cursor)) return false;
427410
Cursor cursor = (Cursor) object;
428-
return device == cursor.device && handle == cursor.handle;
411+
return device == cursor.device && win32_getHandle(this, DEFAULT_ZOOM) == win32_getHandle(cursor, DEFAULT_ZOOM);
429412
}
430413

431414
/**
@@ -440,7 +423,7 @@ public boolean equals (Object object) {
440423
*/
441424
@Override
442425
public int hashCode () {
443-
return (int)handle;
426+
return win32_getHandle(this, DEFAULT_ZOOM).intValue();
444427
}
445428

446429
/**
@@ -455,7 +438,7 @@ public int hashCode () {
455438
*/
456439
@Override
457440
public boolean isDisposed() {
458-
return handle == 0;
441+
return isDestroyed;
459442
}
460443

461444
/**
@@ -467,7 +450,7 @@ public boolean isDisposed() {
467450
@Override
468451
public String toString () {
469452
if (isDisposed()) return "Cursor {*DISPOSED*}";
470-
return "Cursor {" + handle + "}";
453+
return "Cursor {" + zoomLevelToHandle + "}";
471454
}
472455

473456
@Override
@@ -531,19 +514,23 @@ private static interface CursorHandleProvider {
531514
}
532515

533516
private static class StyleCursorHandleProvider implements CursorHandleProvider {
534-
private final int style;
517+
private final long lpCursorName;
535518

536519
public StyleCursorHandleProvider(int style) {
537-
this.style = style;
520+
this.lpCursorName = setupCursorFromStyle(style);
538521
}
539522

540523
@Override
541524
public CursorHandle createHandle(Device device, int zoom) {
542525
// zoom ignored, LoadCursor handles scaling internally
543-
return setupCursorFromStyle(this.style);
526+
long handle = OS.LoadCursor(0, lpCursorName);
527+
if (handle == 0) {
528+
SWT.error(SWT.ERROR_NO_HANDLES);
529+
}
530+
return new CustomCursorHandle(handle);
544531
}
545532

546-
private static final CursorHandle setupCursorFromStyle(int style) {
533+
private static final long setupCursorFromStyle(int style) {
547534
long lpCursorName = 0;
548535
switch (style) {
549536
case SWT.CURSOR_HAND:
@@ -615,11 +602,7 @@ private static final CursorHandle setupCursorFromStyle(int style) {
615602
default:
616603
SWT.error(SWT.ERROR_INVALID_ARGUMENT);
617604
}
618-
long handle = OS.LoadCursor(0, lpCursorName);
619-
if (handle == 0) {
620-
SWT.error(SWT.ERROR_NO_HANDLES);
621-
}
622-
return new CustomCursorHandle(handle);
605+
return lpCursorName;
623606
}
624607
}
625608

@@ -646,6 +629,13 @@ private static class ImageDataProviderCursorHandleProvider extends HotspotAwareC
646629

647630
public ImageDataProviderCursorHandleProvider(ImageDataProvider provider, int hotspotX, int hotspotY) {
648631
super(hotspotX, hotspotY);
632+
ImageData source = provider.getImageData(DEFAULT_ZOOM);
633+
if (source == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
634+
/* Check the hotspots */
635+
if (hotspotX >= source.width || hotspotX < 0 ||
636+
hotspotY >= source.height || hotspotY < 0) {
637+
SWT.error(SWT.ERROR_INVALID_ARGUMENT);
638+
}
649639
this.provider = provider;
650640
}
651641

@@ -668,6 +658,12 @@ private static class ImageDataCursorHandleProvider extends HotspotAwareCursorHan
668658

669659
public ImageDataCursorHandleProvider(ImageData source, int hotspotX, int hotspotY) {
670660
super(hotspotX, hotspotY);
661+
if (source == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
662+
/* Check the hotspots */
663+
if (hotspotX >= source.width || hotspotX < 0 ||
664+
hotspotY >= source.height || hotspotY < 0) {
665+
SWT.error(SWT.ERROR_INVALID_ARGUMENT);
666+
}
671667
this.source = source;
672668
}
673669

@@ -684,6 +680,16 @@ private static class ImageDataWithMaskCursorHandleProvider extends ImageDataCurs
684680

685681
public ImageDataWithMaskCursorHandleProvider(ImageData source, ImageData mask, int hotspotX, int hotspotY) {
686682
super(source, hotspotX, hotspotY);
683+
if (mask == null) {
684+
if (source.getTransparencyType() != SWT.TRANSPARENCY_MASK) {
685+
SWT.error(SWT.ERROR_NULL_ARGUMENT);
686+
}
687+
mask = source.getTransparencyMask();
688+
}
689+
/* Check the bounds. Mask must be the same size as source */
690+
if (mask.width != source.width || mask.height != source.height) {
691+
SWT.error(SWT.ERROR_INVALID_ARGUMENT);
692+
}
687693
this.mask = mask;
688694
}
689695

tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_graphics_Cursor.java

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717

1818
import static org.junit.Assert.assertNotNull;
19+
import static org.junit.Assert.assertThrows;
1920
import static org.junit.Assert.assertTrue;
2021
import static org.junit.Assert.fail;
2122

@@ -28,6 +29,8 @@
2829
import org.eclipse.swt.graphics.ImageData;
2930
import org.eclipse.swt.graphics.ImageDataProvider;
3031
import org.eclipse.swt.graphics.ImageLoader;
32+
import org.eclipse.swt.graphics.PaletteData;
33+
import org.eclipse.swt.graphics.RGB;
3134
import org.eclipse.swt.widgets.Display;
3235
import org.junit.Before;
3336
import org.junit.Test;
@@ -172,6 +175,66 @@ public void test_ConstructorWithImageDataProvider() {
172175
}
173176
}
174177

178+
@Test
179+
public void test_InvalidArgumentsForAllConstructors() {
180+
ImageData source = new ImageData(16, 16, 1, new PaletteData(new RGB[] { new RGB(0, 0, 0) }));
181+
ImageData mask = new ImageData(16, 16, 1, new PaletteData(new RGB[] { new RGB(0, 0, 0) }));
182+
183+
assertThrows("IllegalArgumentException Expected: when wrong style was provided", IllegalArgumentException.class,
184+
() -> {
185+
Cursor cursor = new Cursor(Display.getDefault(), -99);
186+
cursor.dispose();
187+
});
188+
189+
assertThrows("IllegalArgumentException Expected: when source is null", IllegalArgumentException.class, () -> {
190+
Cursor cursorFromImageAndMask = new Cursor(Display.getDefault(), null, mask, 0, 0);
191+
cursorFromImageAndMask.dispose();
192+
});
193+
194+
assertThrows("IllegalArgumentException Expected: when mask is null and source doesn't heve a mask",
195+
IllegalArgumentException.class, () -> {
196+
Cursor cursorFromImageAndMask = new Cursor(Display.getDefault(), source, null, 0, 0);
197+
cursorFromImageAndMask.dispose();
198+
});
199+
200+
assertThrows("IllegalArgumentException Expected: when source and the mask are not the same size",
201+
IllegalArgumentException.class, () -> {
202+
ImageData source32 = new ImageData(32, 32, 1, new PaletteData(new RGB[] { new RGB(0, 0, 0) }));
203+
ImageData mask16 = new ImageData(16, 16, 1, new PaletteData(new RGB[] { new RGB(0, 0, 0) }));
204+
205+
Cursor cursorFromImageAndMask = new Cursor(Display.getDefault(), source32, mask16, 0, 0);
206+
cursorFromImageAndMask.dispose();
207+
});
208+
209+
assertThrows("IllegalArgumentException Expected: when hotspot is outside the bounds of the image",
210+
IllegalArgumentException.class, () -> {
211+
Cursor cursorFromImageAndMask = new Cursor(Display.getDefault(), source, mask, 18, 18);
212+
cursorFromImageAndMask.dispose();
213+
});
214+
215+
assertThrows("IllegalArgumentException Expected: when source image data is null", IllegalArgumentException.class,
216+
() -> {
217+
ImageData nullImageData = null;
218+
Cursor cursorFromSourceOnly = new Cursor(Display.getDefault(), nullImageData, 0, 0);
219+
cursorFromSourceOnly.dispose();
220+
});
221+
222+
assertThrows("IllegalArgumentException Expected: when ImageDataProvider is null", IllegalArgumentException.class,
223+
() -> {
224+
ImageDataProvider provider = null;
225+
Cursor cursorFromProvider = new Cursor(Display.getDefault(), provider, 0, 0);
226+
cursorFromProvider.dispose();
227+
});
228+
229+
assertThrows("IllegalArgumentException Expected: when source in ImageDataProvider is null",
230+
IllegalArgumentException.class, () -> {
231+
ImageData nullSource = null;
232+
ImageDataProvider provider = zoom -> nullSource;
233+
Cursor cursorFromProvider = new Cursor(Display.getDefault(), provider, 0, 0);
234+
cursorFromProvider.dispose();
235+
});
236+
}
237+
175238
@Test
176239
public void test_equalsLjava_lang_Object() {
177240
/* Note: Two cursors are only considered equal if their handles are equal.

0 commit comments

Comments
 (0)