diff --git a/org.eclipse.gef/src/org/eclipse/gef/SharedCursors.java b/org.eclipse.gef/src/org/eclipse/gef/SharedCursors.java index 4bceed9d1..86a2055b4 100644 --- a/org.eclipse.gef/src/org/eclipse/gef/SharedCursors.java +++ b/org.eclipse.gef/src/org/eclipse/gef/SharedCursors.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2010 IBM Corporation and others. + * Copyright (c) 2000, 2024 IBM Corporation and others. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License 2.0 which is available at @@ -15,10 +15,11 @@ import org.eclipse.swt.graphics.Cursor; import org.eclipse.jface.resource.ImageDescriptor; -import org.eclipse.core.runtime.Platform; + import org.eclipse.draw2d.Cursors; import org.eclipse.gef.internal.Internal; +import org.eclipse.gef.internal.InternalGEFPlugin; /** * A shared collection of Cursors. @@ -44,8 +45,6 @@ public class SharedCursors extends Cursors { */ public static final Cursor CURSOR_TREE_MOVE; - private static int deviceZoom = -1; - static { CURSOR_PLUG = createCursor("icons/plug-cursor.png"); //$NON-NLS-1$ CURSOR_PLUG_NOT = createCursor("icons/plugnot-cursor.png"); //$NON-NLS-1$ @@ -55,26 +54,8 @@ public class SharedCursors extends Cursors { private static Cursor createCursor(String sourceName) { ImageDescriptor src = ImageDescriptor.createFromFile(Internal.class, sourceName); - return new Cursor(null, src.getImageData(getDeviceZoom()), 0, 0); - } - - private static int getDeviceZoom() { - if (deviceZoom == -1) { - deviceZoom = 100; // default value - String deviceZoomProperty = System.getProperty("org.eclipse.swt.internal.deviceZoom"); //$NON-NLS-1$ - if (deviceZoomProperty != null) { - try { - deviceZoom = Integer.parseInt(deviceZoomProperty); - } catch (NumberFormatException ex) { - // if the property can not be parsed we keep the default 100% zoom level - } - } - } - // On Mac and Linux X11 ImageData for cursors should always be created with 100% device zoom - return Platform.getOS().equals(Platform.OS_MACOSX) || - (Platform.getOS().equals(Platform.OS_LINUX) && "x11".equalsIgnoreCase(System.getenv("XDG_SESSION_TYPE"))) //$NON-NLS-1$ //$NON-NLS-2$ - ? 100 - : deviceZoom; + int deviceZoom = InternalGEFPlugin.getOrDefaultDeviceZoom(); + return new Cursor(null, InternalGEFPlugin.scaledImageData(src, deviceZoom), 0, 0); } } diff --git a/org.eclipse.gef/src/org/eclipse/gef/internal/InternalGEFPlugin.java b/org.eclipse.gef/src/org/eclipse/gef/internal/InternalGEFPlugin.java index 6a6ee9494..a6f38b85c 100644 --- a/org.eclipse.gef/src/org/eclipse/gef/internal/InternalGEFPlugin.java +++ b/org.eclipse.gef/src/org/eclipse/gef/internal/InternalGEFPlugin.java @@ -13,6 +13,11 @@ package org.eclipse.gef.internal; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.ImageData; + +import org.eclipse.core.runtime.Platform; +import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.jface.resource.ImageRegistry; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.plugin.AbstractUIPlugin; @@ -67,4 +72,43 @@ public void stop(BundleContext context) throws Exception { super.stop(context); } + /** + * Convenience method for getting the current zoom level of the active device.If + * on MacOS or Linux (x11 window system) or if the device zoom couldn't + * otherwise be determined, this method returns {@code 100} as default value. + */ + public static int getOrDefaultDeviceZoom() { + // On Mac and Linux X11 ImageData for cursors should always be created with 100% + // device zoom + if (Platform.getOS().equals(Platform.OS_MACOSX) || (Platform.getOS().equals(Platform.OS_LINUX) + && "x11".equalsIgnoreCase(System.getenv("XDG_SESSION_TYPE")))) { //$NON-NLS-1$//$NON-NLS-2$ + return 100; + } + String deviceZoom = System.getProperty("org.eclipse.swt.internal.deviceZoom", "100"); //$NON-NLS-1$ //$NON-NLS-2$ + try { + return Integer.parseInt(deviceZoom); + } catch (NumberFormatException e) { + return 100; + } + } + + /** + * Convenience method to get the image data for a given zoom level. If no image + * for the requested zoom level exists, the image data may be an auto-scaled + * version of the native image and may look blurred or mangled. + */ + public static ImageData scaledImageData(ImageDescriptor descriptor, int zoom) { + // Default case: Image in matching resolution has been found + ImageData data = descriptor.getImageData(zoom); + if (data != null) { + return data; + } + // Otherwise artifically scale the image + Image image = descriptor.createImage(); + try { + return image.getImageData(zoom); + } finally { + image.dispose(); + } + } } diff --git a/org.eclipse.gef/src/org/eclipse/gef/ui/palette/FlyoutPaletteComposite.java b/org.eclipse.gef/src/org/eclipse/gef/ui/palette/FlyoutPaletteComposite.java index cdf23e875..eee58155b 100644 --- a/org.eclipse.gef/src/org/eclipse/gef/ui/palette/FlyoutPaletteComposite.java +++ b/org.eclipse.gef/src/org/eclipse/gef/ui/palette/FlyoutPaletteComposite.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2004, 2010 IBM Corporation and others. + * Copyright (c) 2004, 2024 IBM Corporation and others. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License 2.0 which is available at @@ -32,6 +32,7 @@ import org.eclipse.swt.graphics.Cursor; import org.eclipse.swt.graphics.Font; import org.eclipse.swt.graphics.GC; +import org.eclipse.swt.graphics.ImageData; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.widgets.Canvas; @@ -84,6 +85,7 @@ import org.eclipse.gef.GraphicalViewer; import org.eclipse.gef.dnd.TemplateTransfer; import org.eclipse.gef.internal.GEFMessages; +import org.eclipse.gef.internal.InternalGEFPlugin; import org.eclipse.gef.internal.InternalImages; import org.eclipse.gef.internal.ui.palette.PaletteColorUtil; import org.eclipse.gef.ui.views.palette.PaletteView; @@ -1557,37 +1559,44 @@ private static class DragCursors { * @return the cursor */ public static Cursor getCursor(int code) { - Display display = Display.getCurrent(); if (cursors[code] == null) { - ImageDescriptor source = null; - ImageDescriptor mask = null; switch (code) { case LEFT: - source = PlatformUI.getWorkbench().getSharedImages() - .getImageDescriptor(ISharedImages.IMG_OBJS_DND_LEFT_SOURCE); - mask = PlatformUI.getWorkbench().getSharedImages() - .getImageDescriptor(ISharedImages.IMG_OBJS_DND_LEFT_MASK); - cursors[LEFT] = new Cursor(display, source.getImageData(), mask.getImageData(), 16, 16); + cursors[LEFT] = createCursor(ISharedImages.IMG_OBJS_DND_LEFT_SOURCE, + ISharedImages.IMG_OBJS_DND_LEFT_MASK); break; case RIGHT: - source = PlatformUI.getWorkbench().getSharedImages() - .getImageDescriptor(ISharedImages.IMG_OBJS_DND_RIGHT_SOURCE); - mask = PlatformUI.getWorkbench().getSharedImages() - .getImageDescriptor(ISharedImages.IMG_OBJS_DND_RIGHT_MASK); - cursors[RIGHT] = new Cursor(display, source.getImageData(), mask.getImageData(), 16, 16); + cursors[RIGHT] = createCursor(ISharedImages.IMG_OBJS_DND_RIGHT_SOURCE, + ISharedImages.IMG_OBJS_DND_RIGHT_MASK); break; default: case INVALID: - source = PlatformUI.getWorkbench().getSharedImages() - .getImageDescriptor(ISharedImages.IMG_OBJS_DND_INVALID_SOURCE); - mask = PlatformUI.getWorkbench().getSharedImages() - .getImageDescriptor(ISharedImages.IMG_OBJS_DND_INVALID_MASK); - cursors[INVALID] = new Cursor(display, source.getImageData(), mask.getImageData(), 16, 16); + cursors[INVALID] = createCursor(ISharedImages.IMG_OBJS_DND_INVALID_SOURCE, + ISharedImages.IMG_OBJS_DND_INVALID_MASK); break; } } return cursors[code]; } + /** + * Creates a new cursor using the shared images as source and mask, + * respectively. The cursors are created with respect to the current device + * zoom, with the hotspot being the center of the image.
+ * The strings passed as arguments must belong to the source and mask ids of a + * cursor contributed by {@link ISharedImages}. + */ + private static Cursor createCursor(String sourceName, String maskName) { + ImageDescriptor source = PlatformUI.getWorkbench().getSharedImages().getImageDescriptor(sourceName); + ImageDescriptor mask = PlatformUI.getWorkbench().getSharedImages().getImageDescriptor(maskName); + int deviceZoom = InternalGEFPlugin.getOrDefaultDeviceZoom(); + // Scales the image if the display is using neither 100% nor 200% zoom + ImageData sourceData = InternalGEFPlugin.scaledImageData(source, deviceZoom); + ImageData maskData = InternalGEFPlugin.scaledImageData(mask, deviceZoom); + // Hotspot should be the center of the image. e.g. (16, 16) on 100% zoom + int hotspotX = sourceData.width / 2; + int hotspotY = sourceData.height / 2; + return new Cursor(null, sourceData, maskData, hotspotX, hotspotY); + } } } \ No newline at end of file