Skip to content

Commit

Permalink
Non system cursors adaption to DPI scale changes
Browse files Browse the repository at this point in the history
Creating a map to provide different handle w.r.t the current zoom of the
display. The method win32_getHandle provides the appropriate handle for
the scaled image as per requested by the client.
  • Loading branch information
ShahzaibIbrahim committed Nov 27, 2024
1 parent e6588c2 commit 5d07820
Show file tree
Hide file tree
Showing 5 changed files with 108 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@
package org.eclipse.swt.graphics;


import java.util.*;

import org.eclipse.swt.*;
import org.eclipse.swt.internal.*;
import org.eclipse.swt.internal.win32.*;

/**
Expand Down Expand Up @@ -56,17 +59,30 @@ public final class Cursor extends Resource {
* platforms and should never be accessed from application code.
* </p>
*
* @noreference This field is not intended to be referenced by clients.
*/
public long handle;
private long handle;
/**
* Attribute to cache current native zoom level
*/
private static final int DEFAULT_ZOOM = 100;

boolean isIcon;
private HashMap<Integer, Long> zoomLevelToHandle = new HashMap<>();

boolean isIcon;
private final ImageData source;
private final ImageData mask;
private final int hotspotX;
private final int hotspotY;
/**
* Prevents uninitialized instances from being created outside the package.
*/
Cursor(Device device) {
super(device);
this.source = null;
this.mask = null;
this.hotspotX = -1;
this.hotspotY = -1;
this.device.registerResourceWithZoomSupport(this);
}

/**
Expand Down Expand Up @@ -116,7 +132,7 @@ public final class Cursor extends Resource {
* @see #dispose()
*/
public Cursor(Device device, int style) {
super(device);
this(device);
long lpCursorName = 0;
switch (style) {
case SWT.CURSOR_HAND: lpCursorName = OS.IDC_HAND; break;
Expand Down Expand Up @@ -184,6 +200,10 @@ public Cursor(Device device, int style) {
*/
public Cursor(Device device, ImageData source, ImageData mask, int hotspotX, int hotspotY) {
super(device);
this.source = source;
this.mask = mask;
this.hotspotX = hotspotX;
this.hotspotY = hotspotY;
if (source == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
if (mask == null) {
if (source.getTransparencyType() != SWT.TRANSPARENCY_MASK) {
Expand Down Expand Up @@ -213,6 +233,7 @@ public Cursor(Device device, ImageData source, ImageData mask, int hotspotX, int
handle = OS.CreateCursor(hInst, hotspotX, hotspotY, source.width, source.height, sourceData, maskData);
if (handle == 0) SWT.error(SWT.ERROR_NO_HANDLES);
init();
this.device.registerResourceWithZoomSupport(this);
}

/**
Expand Down Expand Up @@ -246,6 +267,10 @@ public Cursor(Device device, ImageData source, ImageData mask, int hotspotX, int
*/
public Cursor(Device device, ImageData source, int hotspotX, int hotspotY) {
super(device);
this.source = source;
this.mask = null;
this.hotspotX = hotspotX;
this.hotspotY = hotspotY;
if (source == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
/* Check the hotspots */
if (hotspotX >= source.width || hotspotX < 0 ||
Expand Down Expand Up @@ -317,6 +342,56 @@ public Cursor(Device device, ImageData source, int hotspotX, int hotspotY) {
if (handle == 0) SWT.error(SWT.ERROR_NO_HANDLES);
isIcon = true;
init();
this.device.registerResourceWithZoomSupport(this);
}

/**
* <b>IMPORTANT:</b> This method is not part of the public
* API for Image. It is marked public only so that it
* can be shared within the packages provided by SWT. It is not
* available on all platforms, and should never be called from
* application code.
*
* Get the handle for a cursor given a zoom level.
*
* @param cursor the cursor
* @param zoom zoom level (in %) of the monitor the cursor is currently in.
*
* @return The handle of the cursor.
*
* @noreference This method is not intended to be referenced by clients.
*/
public static Long win32_getHandle (Cursor cursor, int zoom) {
if (cursor.isDisposed()) {
return cursor.handle;
}
if (cursor.zoomLevelToHandle.get(zoom) != null) {
return cursor.zoomLevelToHandle.get(zoom);
}

if (cursor.source == null) {
cursor.setHandleForZoomLevel(cursor.handle, zoom);
} else {
ImageData source = DPIUtil.scaleImageData(cursor.device, cursor.source, zoom, DEFAULT_ZOOM);
if (cursor.isIcon) {
Cursor newCursor = new Cursor(cursor.device, source, cursor.hotspotX, cursor.hotspotY);
cursor.setHandleForZoomLevel(newCursor.handle, zoom);
} else {
ImageData mask = DPIUtil.scaleImageData(cursor.device, cursor.mask, zoom, DEFAULT_ZOOM);
Cursor newCursor = new Cursor(cursor.device, source, mask, cursor.hotspotX, cursor.hotspotY);
cursor.setHandleForZoomLevel(newCursor.handle, zoom);
}
}
return cursor.zoomLevelToHandle.get(zoom);
}

private void setHandleForZoomLevel(long handle, Integer zoom) {
if (this.handle == 0) {
this.handle = handle; // Set handle for default zoom level
}
if (zoom != null && !zoomLevelToHandle.containsKey(zoom)) {
zoomLevelToHandle.put(zoom, handle);
}
}

@Override
Expand All @@ -333,7 +408,19 @@ void destroy () {
// if (OS.GetCursor() == handle) {
// OS.SetCursor(OS.LoadCursor(0, OS.IDC_ARROW));
// }
device.deregisterResourceWithZoomSupport(this);
destroyHandle();
}

private void destroyHandle () {
for (Long handle : zoomLevelToHandle.values()) {
destroyHandle(handle);
}
zoomLevelToHandle.clear();
handle = 0;
}

private void destroyHandle(long handle) {
if (isIcon) {
OS.DestroyIcon(handle);
} else {
Expand All @@ -347,7 +434,6 @@ void destroy () {
*/
OS.DestroyCursor(handle);
}
handle = 0;
}

/**
Expand Down Expand Up @@ -410,6 +496,18 @@ public String toString () {
return "Cursor {" + handle + "}";
}

@Override
void destroyHandlesExcept(Set<Integer> zoomLevels) {
zoomLevelToHandle.entrySet().removeIf(entry -> {
final Integer zoom = entry.getKey();
if (!zoomLevels.contains(zoom) && zoom != DPIUtil.getZoomForAutoscaleProperty(DEFAULT_ZOOM)) {
destroyHandle(entry.getValue());
return true;
}
return false;
});
}

/**
* Invokes platform specific functionality to allocate a new cursor.
* <p>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5417,7 +5417,7 @@ LRESULT WM_SETCURSOR (long wParam, long lParam) {
if (control == null) return null;
Cursor cursor = control.findCursor ();
if (cursor != null) {
OS.SetCursor (cursor.handle);
OS.SetCursor (Cursor.win32_getHandle(cursor, getZoom()));
return LRESULT.ONE;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2624,7 +2624,7 @@ LRESULT WM_SETCURSOR (long wParam, long lParam) {
RECT rect = new RECT ();
OS.GetClientRect (handle, rect);
if (OS.PtInRect (rect, pt)) {
OS.SetCursor (cursor.handle);
OS.SetCursor (Cursor.win32_getHandle(cursor, getZoom()));
switch (msg) {
case OS.WM_LBUTTONDOWN:
case OS.WM_RBUTTONDOWN:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -823,7 +823,7 @@ public void setCursor(Cursor newCursor) {
checkWidget();
clientCursor = newCursor;
if (newCursor != null) {
if (inEvent) OS.SetCursor (clientCursor.handle);
if (inEvent) OS.SetCursor (Cursor.win32_getHandle(clientCursor, getZoom()));
}
}

Expand Down Expand Up @@ -892,7 +892,7 @@ long transparentProc (long hwnd, long msg, long wParam, long lParam) {
break;
case OS.WM_SETCURSOR:
if (clientCursor != null) {
OS.SetCursor (clientCursor.handle);
OS.SetCursor (Cursor.win32_getHandle(clientCursor, getZoom()));
return 1;
}
if (resizeCursor != 0) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4663,7 +4663,7 @@ void setCursor () {
* is IDC_ARROW.
*/
Cursor cursor = findCursor ();
long hCursor = cursor == null ? OS.LoadCursor (0, OS.IDC_ARROW) : cursor.handle;
long hCursor = cursor == null ? OS.LoadCursor (0, OS.IDC_ARROW) : Cursor.win32_getHandle(cursor, getZoom());
OS.SetCursor (hCursor);
}

Expand Down

0 comments on commit 5d07820

Please sign in to comment.