14
14
package org .eclipse .swt .graphics ;
15
15
16
16
17
+ import java .util .*;
18
+
17
19
import org .eclipse .swt .*;
20
+ import org .eclipse .swt .internal .*;
18
21
import org .eclipse .swt .internal .win32 .*;
19
22
20
23
/**
@@ -56,17 +59,30 @@ public final class Cursor extends Resource {
56
59
* platforms and should never be accessed from application code.
57
60
* </p>
58
61
*
59
- * @noreference This field is not intended to be referenced by clients.
60
62
*/
61
- public long handle ;
63
+ private long handle ;
64
+ /**
65
+ * Attribute to cache current native zoom level
66
+ */
67
+ private static final int DEFAULT_ZOOM = 100 ;
62
68
63
- boolean isIcon ;
69
+ private HashMap < Integer , Long > zoomLevelToHandle = new HashMap <>() ;
64
70
71
+ boolean isIcon ;
72
+ private final ImageData source ;
73
+ private final ImageData mask ;
74
+ private final int hotspotX ;
75
+ private final int hotspotY ;
65
76
/**
66
77
* Prevents uninitialized instances from being created outside the package.
67
78
*/
68
79
Cursor (Device device ) {
69
80
super (device );
81
+ this .source = null ;
82
+ this .mask = null ;
83
+ this .hotspotX = -1 ;
84
+ this .hotspotY = -1 ;
85
+ this .device .registerResourceWithZoomSupport (this );
70
86
}
71
87
72
88
/**
@@ -116,7 +132,7 @@ public final class Cursor extends Resource {
116
132
* @see #dispose()
117
133
*/
118
134
public Cursor (Device device , int style ) {
119
- super (device );
135
+ this (device );
120
136
long lpCursorName = 0 ;
121
137
switch (style ) {
122
138
case SWT .CURSOR_HAND : lpCursorName = OS .IDC_HAND ; break ;
@@ -184,6 +200,10 @@ public Cursor(Device device, int style) {
184
200
*/
185
201
public Cursor (Device device , ImageData source , ImageData mask , int hotspotX , int hotspotY ) {
186
202
super (device );
203
+ this .source = source ;
204
+ this .mask = mask ;
205
+ this .hotspotX = hotspotX ;
206
+ this .hotspotY = hotspotY ;
187
207
if (source == null ) SWT .error (SWT .ERROR_NULL_ARGUMENT );
188
208
if (mask == null ) {
189
209
if (source .getTransparencyType () != SWT .TRANSPARENCY_MASK ) {
@@ -213,6 +233,7 @@ public Cursor(Device device, ImageData source, ImageData mask, int hotspotX, int
213
233
handle = OS .CreateCursor (hInst , hotspotX , hotspotY , source .width , source .height , sourceData , maskData );
214
234
if (handle == 0 ) SWT .error (SWT .ERROR_NO_HANDLES );
215
235
init ();
236
+ this .device .registerResourceWithZoomSupport (this );
216
237
}
217
238
218
239
/**
@@ -246,6 +267,10 @@ public Cursor(Device device, ImageData source, ImageData mask, int hotspotX, int
246
267
*/
247
268
public Cursor (Device device , ImageData source , int hotspotX , int hotspotY ) {
248
269
super (device );
270
+ this .source = source ;
271
+ this .mask = null ;
272
+ this .hotspotX = hotspotX ;
273
+ this .hotspotY = hotspotY ;
249
274
if (source == null ) SWT .error (SWT .ERROR_NULL_ARGUMENT );
250
275
/* Check the hotspots */
251
276
if (hotspotX >= source .width || hotspotX < 0 ||
@@ -317,6 +342,56 @@ public Cursor(Device device, ImageData source, int hotspotX, int hotspotY) {
317
342
if (handle == 0 ) SWT .error (SWT .ERROR_NO_HANDLES );
318
343
isIcon = true ;
319
344
init ();
345
+ this .device .registerResourceWithZoomSupport (this );
346
+ }
347
+
348
+ /**
349
+ * <b>IMPORTANT:</b> This method is not part of the public
350
+ * API for Image. It is marked public only so that it
351
+ * can be shared within the packages provided by SWT. It is not
352
+ * available on all platforms, and should never be called from
353
+ * application code.
354
+ *
355
+ * Get the handle for a cursor given a zoom level.
356
+ *
357
+ * @param cursor the cursor
358
+ * @param zoom zoom level (in %) of the monitor the cursor is currently in.
359
+ *
360
+ * @return The handle of the cursor.
361
+ *
362
+ * @noreference This method is not intended to be referenced by clients.
363
+ */
364
+ public static Long win32_getHandle (Cursor cursor , int zoom ) {
365
+ if (cursor .isDisposed ()) {
366
+ return cursor .handle ;
367
+ }
368
+ if (cursor .zoomLevelToHandle .get (zoom ) != null ) {
369
+ return cursor .zoomLevelToHandle .get (zoom );
370
+ }
371
+
372
+ if (cursor .source == null ) {
373
+ cursor .setHandleForZoomLevel (cursor .handle , zoom );
374
+ } else {
375
+ ImageData source = DPIUtil .scaleImageData (cursor .device , cursor .source , zoom , DEFAULT_ZOOM );
376
+ if (cursor .isIcon ) {
377
+ Cursor newCursor = new Cursor (cursor .device , source , cursor .hotspotX , cursor .hotspotY );
378
+ cursor .setHandleForZoomLevel (newCursor .handle , zoom );
379
+ } else {
380
+ ImageData mask = DPIUtil .scaleImageData (cursor .device , cursor .mask , zoom , DEFAULT_ZOOM );
381
+ Cursor newCursor = new Cursor (cursor .device , source , mask , cursor .hotspotX , cursor .hotspotY );
382
+ cursor .setHandleForZoomLevel (newCursor .handle , zoom );
383
+ }
384
+ }
385
+ return cursor .zoomLevelToHandle .get (zoom );
386
+ }
387
+
388
+ private void setHandleForZoomLevel (long handle , Integer zoom ) {
389
+ if (this .handle == 0 ) {
390
+ this .handle = handle ; // Set handle for default zoom level
391
+ }
392
+ if (zoom != null && !zoomLevelToHandle .containsKey (zoom )) {
393
+ zoomLevelToHandle .put (zoom , handle );
394
+ }
320
395
}
321
396
322
397
@ Override
@@ -333,7 +408,19 @@ void destroy () {
333
408
// if (OS.GetCursor() == handle) {
334
409
// OS.SetCursor(OS.LoadCursor(0, OS.IDC_ARROW));
335
410
// }
411
+ device .deregisterResourceWithZoomSupport (this );
412
+ destroyHandle ();
413
+ }
336
414
415
+ private void destroyHandle () {
416
+ for (Long handle : zoomLevelToHandle .values ()) {
417
+ destroyHandle (handle );
418
+ }
419
+ zoomLevelToHandle .clear ();
420
+ handle = 0 ;
421
+ }
422
+
423
+ private void destroyHandle (long handle ) {
337
424
if (isIcon ) {
338
425
OS .DestroyIcon (handle );
339
426
} else {
@@ -347,7 +434,6 @@ void destroy () {
347
434
*/
348
435
OS .DestroyCursor (handle );
349
436
}
350
- handle = 0 ;
351
437
}
352
438
353
439
/**
@@ -410,6 +496,18 @@ public String toString () {
410
496
return "Cursor {" + handle + "}" ;
411
497
}
412
498
499
+ @ Override
500
+ void destroyHandlesExcept (Set <Integer > zoomLevels ) {
501
+ zoomLevelToHandle .entrySet ().removeIf (entry -> {
502
+ final Integer zoom = entry .getKey ();
503
+ if (!zoomLevels .contains (zoom ) && zoom != DPIUtil .getZoomForAutoscaleProperty (DEFAULT_ZOOM )) {
504
+ destroyHandle (entry .getValue ());
505
+ return true ;
506
+ }
507
+ return false ;
508
+ });
509
+ }
510
+
413
511
/**
414
512
* Invokes platform specific functionality to allocate a new cursor.
415
513
* <p>
0 commit comments