1414package org .eclipse .swt .graphics ;
1515
1616
17+ import java .util .*;
18+
1719import org .eclipse .swt .*;
20+ import org .eclipse .swt .internal .*;
1821import org .eclipse .swt .internal .win32 .*;
1922
2023/**
@@ -56,17 +59,30 @@ public final class Cursor extends Resource {
5659 * platforms and should never be accessed from application code.
5760 * </p>
5861 *
59- * @noreference This field is not intended to be referenced by clients.
6062 */
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 ;
6268
63- boolean isIcon ;
69+ private HashMap < Integer , Long > zoomLevelToHandle = new HashMap <>() ;
6470
71+ boolean isIcon ;
72+ private final ImageData source ;
73+ private final ImageData mask ;
74+ private final int hotspotX ;
75+ private final int hotspotY ;
6576/**
6677 * Prevents uninitialized instances from being created outside the package.
6778 */
6879Cursor (Device device ) {
6980 super (device );
81+ this .source = null ;
82+ this .mask = null ;
83+ this .hotspotX = -1 ;
84+ this .hotspotY = -1 ;
85+ this .device .registerResourceWithZoomSupport (this );
7086}
7187
7288/**
@@ -116,7 +132,7 @@ public final class Cursor extends Resource {
116132 * @see #dispose()
117133 */
118134public Cursor (Device device , int style ) {
119- super (device );
135+ this (device );
120136 long lpCursorName = 0 ;
121137 switch (style ) {
122138 case SWT .CURSOR_HAND : lpCursorName = OS .IDC_HAND ; break ;
@@ -184,6 +200,10 @@ public Cursor(Device device, int style) {
184200 */
185201public Cursor (Device device , ImageData source , ImageData mask , int hotspotX , int hotspotY ) {
186202 super (device );
203+ this .source = source ;
204+ this .mask = mask ;
205+ this .hotspotX = hotspotX ;
206+ this .hotspotY = hotspotY ;
187207 if (source == null ) SWT .error (SWT .ERROR_NULL_ARGUMENT );
188208 if (mask == null ) {
189209 if (source .getTransparencyType () != SWT .TRANSPARENCY_MASK ) {
@@ -213,6 +233,7 @@ public Cursor(Device device, ImageData source, ImageData mask, int hotspotX, int
213233 handle = OS .CreateCursor (hInst , hotspotX , hotspotY , source .width , source .height , sourceData , maskData );
214234 if (handle == 0 ) SWT .error (SWT .ERROR_NO_HANDLES );
215235 init ();
236+ this .device .registerResourceWithZoomSupport (this );
216237}
217238
218239/**
@@ -246,6 +267,10 @@ public Cursor(Device device, ImageData source, ImageData mask, int hotspotX, int
246267 */
247268public Cursor (Device device , ImageData source , int hotspotX , int hotspotY ) {
248269 super (device );
270+ this .source = source ;
271+ this .mask = null ;
272+ this .hotspotX = hotspotX ;
273+ this .hotspotY = hotspotY ;
249274 if (source == null ) SWT .error (SWT .ERROR_NULL_ARGUMENT );
250275 /* Check the hotspots */
251276 if (hotspotX >= source .width || hotspotX < 0 ||
@@ -317,6 +342,56 @@ public Cursor(Device device, ImageData source, int hotspotX, int hotspotY) {
317342 if (handle == 0 ) SWT .error (SWT .ERROR_NO_HANDLES );
318343 isIcon = true ;
319344 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+ }
320395}
321396
322397@ Override
@@ -333,7 +408,19 @@ void destroy () {
333408// if (OS.GetCursor() == handle) {
334409// OS.SetCursor(OS.LoadCursor(0, OS.IDC_ARROW));
335410// }
411+ device .deregisterResourceWithZoomSupport (this );
412+ destroyHandle ();
413+ }
336414
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 ) {
337424 if (isIcon ) {
338425 OS .DestroyIcon (handle );
339426 } else {
@@ -347,7 +434,6 @@ void destroy () {
347434 */
348435 OS .DestroyCursor (handle );
349436 }
350- handle = 0 ;
351437}
352438
353439/**
@@ -410,6 +496,18 @@ public String toString () {
410496 return "Cursor {" + handle + "}" ;
411497}
412498
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+
413511/**
414512 * Invokes platform specific functionality to allocate a new cursor.
415513 * <p>
0 commit comments