Skip to content

Commit 6b82f88

Browse files
committed
[90] Fix cursor initialization when using fractional scaling
Recent Eclipse version support fractional zoom level as opposed to 100% or 200% zoom. Because no icons exist for those levels, an IllegalArgumentException is thrown when trying to create the corresponding cursors. In order to solve this, one has to consider the following cases: 1) Newer SWT versions provide a Cursor constructor that accepts an ImageDataProvider. This constructor always creates image data matching the device zoom. However, this constructor crashes when PNGs are used and the automatic UI scaling is disabled. 2) Older SWT versions automatically upscales the image data to match the device zoom. On Windows, the image data should always be at 100% because SWT internally scales the image to match the device zoom. Sadly, this doesn't work either. So on both Windows and Non-Windows systems, the image must be pre-scaled to the device zoom. This means that on Windows, the cursor is always scaled twice.
1 parent 0be4aeb commit 6b82f88

File tree

1 file changed

+52
-4
lines changed
  • bundles/org.eclipse.gmf.runtime.gef.ui/src/org/eclipse/gmf/runtime/gef/ui/internal/l10n

1 file changed

+52
-4
lines changed

bundles/org.eclipse.gmf.runtime.gef.ui/src/org/eclipse/gmf/runtime/gef/ui/internal/l10n/Cursors.java

Lines changed: 52 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/******************************************************************************
2-
* Copyright (c) 2002, 2003 IBM Corporation and others.
2+
* Copyright (c) 2002, 2025 IBM Corporation and others.
33
* This program and the accompanying materials are made
44
* available under the terms of the Eclipse Public License 2.0
55
* which is available at https://www.eclipse.org/legal/epl-2.0/
@@ -12,7 +12,14 @@
1212

1313
package org.eclipse.gmf.runtime.gef.ui.internal.l10n;
1414

15+
import java.lang.reflect.Constructor;
16+
17+
import org.eclipse.jface.resource.ImageDescriptor;
1518
import org.eclipse.swt.graphics.Cursor;
19+
import org.eclipse.swt.graphics.Device;
20+
import org.eclipse.swt.graphics.Image;
21+
import org.eclipse.swt.graphics.ImageData;
22+
import org.eclipse.swt.graphics.ImageDataProvider;
1623

1724

1825
/**
@@ -37,11 +44,37 @@ public class Cursors {
3744
private static int deviceZoom = -1;
3845

3946
static {
40-
CURSOR_SEG_ADD = new Cursor(null, GefUIPluginImages.DESC_SEG_ADD.getImageData(getDeviceZoom()), 0, 0);
41-
CURSOR_SEG_MOVE = new Cursor(null, GefUIPluginImages.DESC_SEG_MOVE.getImageData(getDeviceZoom()), 0, 0);
47+
CURSOR_SEG_ADD = createCursor(GefUIPluginImages.DESC_SEG_ADD, 0, 0);
48+
CURSOR_SEG_MOVE = createCursor(GefUIPluginImages.DESC_SEG_MOVE, 0, 0);
4249
}
4350

44-
// Taken from org.eclipse.gef.SharedCursors.java
51+
// Taken from org.eclipse.gef.internal.InternalGEFPlugin.java
52+
private static Cursor createCursor(ImageDescriptor source, int hotspotX, int hotspotY) {
53+
ImageDataProvider imageDataProvider = zoom -> getScaledImageData(source, zoom);
54+
try {
55+
// If this system property is disabled, SWT will crash trying to load e.g. the non-existent @1.5.png variant at 150% zoom.
56+
if (isMonitorSpecificScalingActive()) {
57+
Constructor<Cursor> ctor = Cursor.class.getConstructor(Device.class, ImageDataProvider.class, int.class,
58+
int.class);
59+
return ctor.newInstance(null, imageDataProvider, hotspotX, hotspotY);
60+
}
61+
} catch (NoSuchMethodException e) {
62+
// SWT version < 3.131.0
63+
} catch (ReflectiveOperationException e) {
64+
throw new RuntimeException("Failed to instantiate Cursor", e); //$NON-NLS-1$
65+
}
66+
// Note: On Windows, the image data would always need to be created at 100% zoom. Sadly, that doesn't work...
67+
// See https://github.com/eclipse-platform/eclipse.platform.swt/issues/2309
68+
return new Cursor(null, imageDataProvider.getImageData(getDeviceZoom()), hotspotX, hotspotY);
69+
}
70+
71+
// Taken from org.eclipse.swt.internal.DPIUtil
72+
public static boolean isMonitorSpecificScalingActive() {
73+
boolean updateOnRuntimeValue = Boolean.getBoolean ("swt.autoScale.updateOnRuntime"); //$NON-NLS-1$
74+
return updateOnRuntimeValue;
75+
}
76+
77+
// Taken from org.eclipse.gef.SharedCursors.java
4578
private static int getDeviceZoom() {
4679
if (deviceZoom == -1) {
4780
deviceZoom = 100; // default value
@@ -56,4 +89,19 @@ private static int getDeviceZoom() {
5689
}
5790
return deviceZoom;
5891
}
92+
93+
private static ImageData getScaledImageData(ImageDescriptor descriptor, int zoom) {
94+
// Default case: Image in matching resolution has been found
95+
ImageData data = descriptor.getImageData(zoom);
96+
if (data != null) {
97+
return data;
98+
}
99+
// Otherwise artifically scale the image
100+
Image image = descriptor.createImage();
101+
try {
102+
return image.getImageData(zoom);
103+
} finally {
104+
image.dispose();
105+
}
106+
}
59107
}

0 commit comments

Comments
 (0)