diff --git a/binaries/org.eclipse.swt.win32.win32.x86_64/.settings/.api_filters b/binaries/org.eclipse.swt.win32.win32.x86_64/.settings/.api_filters index 5d0ce47678..2f6b29f36a 100644 --- a/binaries/org.eclipse.swt.win32.win32.x86_64/.settings/.api_filters +++ b/binaries/org.eclipse.swt.win32.win32.x86_64/.settings/.api_filters @@ -582,10 +582,11 @@ - + - + + diff --git a/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/CTabFolder.java b/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/CTabFolder.java index 989cf68dfc..951d303d09 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/CTabFolder.java +++ b/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/CTabFolder.java @@ -734,7 +734,7 @@ Image createButtonImage(Display display, int button) { final Rectangle trim = renderer.computeTrim(button, SWT.NONE, 0, 0, 0, 0); final Point imageSize = new Point(size.x - trim.width, size.y - trim.height); Color transColor = renderer.parent.getBackground(); - final ImageGcDrawer imageGcDrawer = new TransparencyColorImageGcDrawer(transColor) { + return new Image(display, imageSize.x, imageSize.y, new TransparencyColorImageGcDrawer(transColor) { @Override public void drawOn(GC gc, int imageWidth, int imageHeight) { Rectangle imageBounds = new Rectangle(0, 0, imageWidth, imageHeight); @@ -742,8 +742,7 @@ public void drawOn(GC gc, int imageWidth, int imageHeight) { gc.fillRectangle(imageBounds); renderer.draw(button, SWT.NONE, imageBounds, gc); } - }; - return new Image(display, imageGcDrawer, imageSize.x, imageSize.y); + }); } private void notifyItemCountChange() { @@ -4007,7 +4006,8 @@ void updateBkImages(boolean colorChanged) { if (colorChanged || !bounds.equals(bkImageBounds[i])) { bkImageBounds[i] = bounds; if (controlBkImages[i] != null) controlBkImages[i].dispose(); - controlBkImages[i] = new Image(control.getDisplay(), (gc, imageWidth, imageHeight) -> renderer.draw(CTabFolderRenderer.PART_BACKGROUND, 0, bounds, gc), bounds.width, bounds.height); + controlBkImages[i] = new Image(control.getDisplay(), bounds.width, bounds.height, + (gc, w, h) -> renderer.draw(CTabFolderRenderer.PART_BACKGROUND, 0, bounds, gc)); control.setBackground(null); control.setBackgroundImage(controlBkImages[i]); } diff --git a/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/StyledText.java b/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/StyledText.java index aa73e8ecd7..ef4f17fc41 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/StyledText.java +++ b/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/StyledText.java @@ -1593,15 +1593,14 @@ void createCaretBitmaps() { leftCaretBitmap.dispose(); } int lineHeight = renderer.getLineHeight(); - final ImageGcDrawer leftCaretDrawer = (gc, width, height) -> { + leftCaretBitmap = new Image(display, caretWidth, lineHeight, (gc, width, height) -> { gc.setBackground(display.getSystemColor(SWT.COLOR_BLACK)); gc.fillRectangle(0, 0, width, height); gc.setForeground(display.getSystemColor(SWT.COLOR_WHITE)); gc.drawLine(0,0,0,height); gc.drawLine(0,0,width-1,0); gc.drawLine(0,1,1,1); - }; - leftCaretBitmap = new Image(display, leftCaretDrawer, caretWidth, lineHeight); + }); if (rightCaretBitmap != null) { if (defaultCaret != null && rightCaretBitmap.equals(defaultCaret.getImage())) { @@ -1609,16 +1608,16 @@ void createCaretBitmaps() { } rightCaretBitmap.dispose(); } - final ImageGcDrawer rightCaretDrawer = (gc, width, height) -> { + rightCaretBitmap = new Image(display, caretWidth, lineHeight, (gc, width, height) -> { gc.setBackground(display.getSystemColor(SWT.COLOR_BLACK)); gc.fillRectangle(0, 0, width, height); gc.setForeground(display.getSystemColor(SWT.COLOR_WHITE)); gc.drawLine(width-1,0,width-1,height); gc.drawLine(0,0,width-1,0); gc.drawLine(width-1,1,1,1); - }; - rightCaretBitmap = new Image(display, rightCaretDrawer, caretWidth, lineHeight); + }); } + /** * Moves the selected text to the clipboard. The text will be put in the * clipboard in plain text, HTML, and RTF formats. diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/Image.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/Image.java index 25ec987f0e..4d83037ed6 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/Image.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/Image.java @@ -142,7 +142,7 @@ public final class Image extends Resource implements Drawable { /** * ImageGcDrawer to provide a callback to draw on a GC for various zoom levels */ - private ImageGcDrawer imageGcDrawer; + private ImageDrawer imageGcDrawer; /** * Style flag used to differentiate normal, gray-scale and disabled images based @@ -878,9 +878,9 @@ public Image(Device device, ImageDataProvider imageDataProvider) { *
  • ERROR_NULL_ARGUMENT - if device is null and there is no current device
  • *
  • ERROR_NULL_ARGUMENT - if the ImageGcDrawer is null
  • * - * @since 3.129 + * @since 3.130 */ -public Image(Device device, ImageGcDrawer imageGcDrawer, int width, int height) { +public Image(Device device, int width, int height, ImageDrawer imageGcDrawer) { super(device); if (imageGcDrawer == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); this.imageGcDrawer = imageGcDrawer; @@ -905,13 +905,22 @@ public Image(Device device, ImageGcDrawer imageGcDrawer, int width, int height) } } -private ImageData drawWithImageGcDrawer(ImageGcDrawer imageGcDrawer, int width, int height, int zoom) { +/** + * @since 3.129 + * @deprecated Instead use {@link #Image(Device, int, int, ImageGcDrawer)} + */ +@Deprecated(forRemoval = true, since = "2025-06 (removal in 2027-06 or later)") +public Image(Device device, ImageGcDrawer imageGcDrawer, int width, int height) { + this(device, width, height, imageGcDrawer); +} + +private ImageData drawWithImageGcDrawer(ImageDrawer imageGcDrawer, int width, int height, int zoom) { Image image = new Image(device, width, height); - GC gc = new GC(image); + GC gc = new GC(image, ExtendedImageDrawer.getGCStyle(imageGcDrawer)); try { imageGcDrawer.drawOn(gc, width, height); ImageData imageData = image.getImageData(zoom); - imageGcDrawer.postProcess(imageData); + ExtendedImageDrawer.postProcess(imageGcDrawer, imageData); return imageData; } finally { gc.dispose(); diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/graphics/ImageDrawer.java b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/graphics/ImageDrawer.java new file mode 100644 index 0000000000..cd4293581c --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/graphics/ImageDrawer.java @@ -0,0 +1,66 @@ +/******************************************************************************* + * Copyright (c) 2025 Yatta and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Yatta - initial API and implementation + *******************************************************************************/ +package org.eclipse.swt.graphics; + +import java.util.function.*; + +import org.eclipse.swt.*; +import org.eclipse.swt.internal.image.*; + +/** + * Interface to provide a callback mechanism to draw on different GC instances + * depending on the zoom the image will be used for. A common use case is when + * the application is moved from a low DPI monitor to a high DPI monitor. This + * provides API which will be called by SWT during the image rendering. + * + * This interface needs to be implemented by client code to provide logic that + * draws on the empty GC on demand. + * + * @since 3.130 + */ +@FunctionalInterface +public interface ImageDrawer { + + /** + * Draws an image on a GC for a requested zoom level. + * + * @param gc The GC will draw on the underlying Image and is configured + * for the targeted zoom + * @param imageWidth The width of the image in points to draw on + * @param imageHeight The height of the image in points to draw on + */ + void drawOn(GC gc, int imageWidth, int imageHeight); + + /** + * @since 3.130 + */ + public static ImageDrawer withGCStyle(int style, ImageDrawer drawer) { + if (drawer instanceof ExtendedImageDrawer extendedDrawer) { + return new ExtendedImageDrawer(extendedDrawer.original(), extendedDrawer.postProcessor(), style); + } + return new ExtendedImageDrawer(drawer, null, style); + } + + /** + * @since 3.130 + */ + public static ImageDrawer create(ImageDrawer drawer, Consumer postProcessor) { + if (drawer instanceof ExtendedImageDrawer extendedDrawer) { + return new ExtendedImageDrawer(extendedDrawer.original(), postProcessor, extendedDrawer.style()); + } + return new ExtendedImageDrawer(drawer, postProcessor, SWT.NONE); + } + + // TODO: or use some kind of builder pattern? +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/graphics/ImageGcDrawer.java b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/graphics/ImageGcDrawer.java index 78388ef93b..89722e53e8 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/graphics/ImageGcDrawer.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/graphics/ImageGcDrawer.java @@ -13,8 +13,6 @@ *******************************************************************************/ package org.eclipse.swt.graphics; -import org.eclipse.swt.*; - /** * Interface to provide a callback mechanism to draw on different GC instances * depending on the zoom the image will be used for. A common use case is when @@ -26,7 +24,8 @@ * * @since 3.129 */ -public interface ImageGcDrawer { +@Deprecated(forRemoval = true, since = "2025-06 (removal in 2027-06 or later)") +public interface ImageGcDrawer extends ImageDrawer { /** * Draws an image on a GC for a requested zoom level. @@ -36,6 +35,7 @@ public interface ImageGcDrawer { * @param imageWidth The width of the image in points to draw on * @param imageHeight The height of the image in points to draw on */ + @Override void drawOn(GC gc, int imageWidth, int imageHeight); /** @@ -47,15 +47,4 @@ public interface ImageGcDrawer { default void postProcess(ImageData imageData) { } - /** - * Returns the GC style used when creating the GC instance. Default - * implementation returns SWT.NONE. - * - * @return the GC style constant - * - * @since 3.130 - */ - default int getGcStyle() { - return SWT.NONE; - } } diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/ExtendedImageDrawer.java b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/ExtendedImageDrawer.java new file mode 100644 index 0000000000..68b02a2997 --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/ExtendedImageDrawer.java @@ -0,0 +1,53 @@ +/******************************************************************************* + * Copyright (c) 2025 Hannes Wellmann and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Hannes Wellmann - initial API and implementation + *******************************************************************************/ + +package org.eclipse.swt.internal.image; + +import java.util.*; +import java.util.function.*; + +import org.eclipse.swt.*; +import org.eclipse.swt.graphics.*; + +public record ExtendedImageDrawer(ImageDrawer original, Consumer postProcessor, int style) + implements ImageDrawer { + + public ExtendedImageDrawer { + Objects.requireNonNull(original); + } + + @Override + public void drawOn(GC gc, int imageWidth, int imageHeight) { + original.drawOn(gc, imageWidth, imageHeight); + } + + public static int getGCStyle(ImageDrawer drawer) { + if (drawer instanceof ExtendedImageDrawer extendedDrawer) { + return extendedDrawer.style(); + } + return SWT.NONE; + } + + public static void postProcess(ImageDrawer drawer, ImageData data) { + if (drawer instanceof @SuppressWarnings("removal") ImageGcDrawer gcDrawer) { + gcDrawer.postProcess(data); + } else if (drawer instanceof ExtendedImageDrawer extendedDrawer) { + Consumer postProcessor2 = extendedDrawer.postProcessor(); + if (postProcessor2 != null) { + postProcessor2.accept(data); + } + } + } + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/graphics/Image.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/graphics/Image.java index 9d69e5a314..27815fb1d9 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/graphics/Image.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/graphics/Image.java @@ -156,7 +156,7 @@ public final class Image extends Resource implements Drawable { /** * ImageGcDrawer to provide a callback to draw on a GC for various zoom levels */ - private ImageGcDrawer imageGcDrawer; + private ImageDrawer imageGcDrawer; /** * Style flag used to differentiate normal, gray-scale and disabled images based @@ -670,9 +670,9 @@ public Image(Device device, ImageDataProvider imageDataProvider) { *
  • ERROR_NULL_ARGUMENT - if device is null and there is no current device
  • *
  • ERROR_NULL_ARGUMENT - if the ImageGcDrawer is null
  • * - * @since 3.129 + * @since 3.130 */ -public Image(Device device, ImageGcDrawer imageGcDrawer, int width, int height) { +public Image(Device device, int width, int height, ImageDrawer imageGcDrawer) { super(device); if (imageGcDrawer == null) { SWT.error(SWT.ERROR_NULL_ARGUMENT); @@ -684,6 +684,15 @@ public Image(Device device, ImageGcDrawer imageGcDrawer, int width, int height) init (); } +/** + * @since 3.129 + * @deprecated Instead use {@link #Image(Device, int, int, ImageGcDrawer)} + */ +@Deprecated(forRemoval = true, since = "2025-06 (removal in 2027-06 or later)") +public Image(Device device, ImageGcDrawer imageGcDrawer, int width, int height) { + this(device, width, height, imageGcDrawer); +} + /** * Refreshes the image for the current device scale factor. *

    @@ -1159,11 +1168,11 @@ public ImageData getImageData (int zoom) { private ImageData drawWithImageGcDrawer(int width, int height, int zoom) { Image image = new Image(device, width, height); - GC gc = new GC(image); + GC gc = new GC(image, ExtendedImageDrawer.getGCStyle(imageGcDrawer)); try { imageGcDrawer.drawOn(gc, width, height); ImageData imageData = image.getImageData(zoom); - imageGcDrawer.postProcess(imageData); + ExtendedImageDrawer.postProcess(imageGcDrawer, imageData); return imageData; } finally { gc.dispose(); diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Image.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Image.java index 6844fe9b43..e3ff610ab4 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Image.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Image.java @@ -629,15 +629,24 @@ public Image(Device device, ImageDataProvider imageDataProvider) { *

  • ERROR_NULL_ARGUMENT - if device is null and there is no current device
  • *
  • ERROR_NULL_ARGUMENT - if the ImageGcDrawer is null
  • * - * @since 3.129 + * @since 3.130 */ -public Image(Device device, ImageGcDrawer imageGcDrawer, int width, int height) { +public Image(Device device, int width, int height, ImageDrawer imageGcDrawer) { super(device); this.imageProvider = new ImageGcDrawerWrapper(imageGcDrawer, width, height); initialNativeZoom = DPIUtil.getNativeDeviceZoom(); init(); } +/** + * @since 3.129 + * @deprecated Instead use {@link #Image(Device, int, int, ImageGcDrawer)} + */ +@Deprecated(forRemoval = true, since = "2025-06 (removal in 2027-06 or later)") +public Image(Device device, ImageGcDrawer imageGcDrawer, int width, int height) { + this(device, width, height, imageGcDrawer); +} + private ImageData adaptImageDataIfDisabledOrGray(ImageData data) { ImageData returnImageData = null; switch (this.styleFlag) { @@ -2476,12 +2485,12 @@ ImageDataProviderWrapper createCopy(Image image) { } private class ImageGcDrawerWrapper extends DynamicImageProviderWrapper { - private ImageGcDrawer drawer; + private ImageDrawer drawer; private int width; private int height; - ImageGcDrawerWrapper(ImageGcDrawer imageGcDrawer, int width, int height) { - checkProvider(imageGcDrawer, ImageGcDrawer.class); + ImageGcDrawerWrapper(ImageDrawer imageGcDrawer, int width, int height) { + checkProvider(imageGcDrawer, ImageDrawer.class); this.drawer = imageGcDrawer; this.width = width; this.height = height; @@ -2502,12 +2511,12 @@ ImageData getImageData(int zoom) { ImageHandle getImageMetadata(int zoom) { initialNativeZoom = zoom; Image image = new Image(device, width, height, zoom); - GC gc = new GC(image, drawer.getGcStyle()); + GC gc = new GC(image, ExtendedImageDrawer.getGCStyle(drawer)); try { gc.data.nativeZoom = zoom; drawer.drawOn(gc, width, height); ImageData imageData = image.getImageMetadata(zoom).getImageData(); - drawer.postProcess(imageData); + ExtendedImageDrawer.postProcess(drawer, imageData); ImageData newData = adaptImageDataIfDisabledOrGray(imageData); init(newData, zoom); } finally {