From 4ab1b1385f45bd96a36faba5d015318721e57efe Mon Sep 17 00:00:00 2001 From: Tobias Melcher Date: Fri, 23 Feb 2024 18:11:43 +0100 Subject: [PATCH] introduce AutoDisposableGC which takes care of creation and disposal of the GC object Fixes: https://github.com/eclipse-platform/eclipse.platform.swt/issues/955 --- .../.settings/.api_filters | 8 ++ .../.settings/.api_filters | 8 ++ .../.settings/.api_filters | 8 ++ .../.settings/.api_filters | 8 ++ .../.settings/.api_filters | 8 ++ .../.settings/.api_filters | 8 ++ .../.settings/.api_filters | 8 ++ .../.settings/.api_filters | 8 ++ .../.settings/.api_filters | 8 ++ .../eclipse/swt/custom/AnimatedProgress.java | 6 +- .../common/org/eclipse/swt/custom/CLabel.java | 19 +-- .../org/eclipse/swt/custom/CTabFolder.java | 127 +++++++++--------- .../swt/custom/StyledTextRenderer.java | 8 +- .../swt/graphics/AutoDisposableGC.java | 18 +++ .../cocoa/org/eclipse/swt/graphics/GC.java | 24 +++- .../cocoa/org/eclipse/swt/graphics/Image.java | 12 +- .../swt/graphics/AutoDisposableGC.java | 18 +++ .../gtk/org/eclipse/swt/graphics/GC.java | 24 +++- .../gtk/org/eclipse/swt/graphics/Image.java | 12 +- .../swt/graphics/AutoDisposableGC.java | 18 +++ .../win32/org/eclipse/swt/graphics/GC.java | 23 +++- .../win32/org/eclipse/swt/graphics/Image.java | 12 +- 22 files changed, 287 insertions(+), 106 deletions(-) create mode 100644 bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/AutoDisposableGC.java create mode 100644 bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/graphics/AutoDisposableGC.java create mode 100644 bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/AutoDisposableGC.java diff --git a/binaries/org.eclipse.swt.cocoa.macosx.aarch64/.settings/.api_filters b/binaries/org.eclipse.swt.cocoa.macosx.aarch64/.settings/.api_filters index 9d7fb794a07..8f717642eb1 100644 --- a/binaries/org.eclipse.swt.cocoa.macosx.aarch64/.settings/.api_filters +++ b/binaries/org.eclipse.swt.cocoa.macosx.aarch64/.settings/.api_filters @@ -1,5 +1,13 @@ + + + + + + + + diff --git a/binaries/org.eclipse.swt.cocoa.macosx.x86_64/.settings/.api_filters b/binaries/org.eclipse.swt.cocoa.macosx.x86_64/.settings/.api_filters index 6af864b828c..724b1e17ea4 100644 --- a/binaries/org.eclipse.swt.cocoa.macosx.x86_64/.settings/.api_filters +++ b/binaries/org.eclipse.swt.cocoa.macosx.x86_64/.settings/.api_filters @@ -1,5 +1,13 @@ + + + + + + + + diff --git a/binaries/org.eclipse.swt.gtk.linux.aarch64/.settings/.api_filters b/binaries/org.eclipse.swt.gtk.linux.aarch64/.settings/.api_filters index 16d019d63e5..34687109f9f 100644 --- a/binaries/org.eclipse.swt.gtk.linux.aarch64/.settings/.api_filters +++ b/binaries/org.eclipse.swt.gtk.linux.aarch64/.settings/.api_filters @@ -1,5 +1,13 @@ + + + + + + + + diff --git a/binaries/org.eclipse.swt.gtk.linux.loongarch64/.settings/.api_filters b/binaries/org.eclipse.swt.gtk.linux.loongarch64/.settings/.api_filters index 307707de690..0703962abd7 100644 --- a/binaries/org.eclipse.swt.gtk.linux.loongarch64/.settings/.api_filters +++ b/binaries/org.eclipse.swt.gtk.linux.loongarch64/.settings/.api_filters @@ -1,5 +1,13 @@ + + + + + + + + diff --git a/binaries/org.eclipse.swt.gtk.linux.ppc64le/.settings/.api_filters b/binaries/org.eclipse.swt.gtk.linux.ppc64le/.settings/.api_filters index d6436a9735e..53053bde804 100644 --- a/binaries/org.eclipse.swt.gtk.linux.ppc64le/.settings/.api_filters +++ b/binaries/org.eclipse.swt.gtk.linux.ppc64le/.settings/.api_filters @@ -1,5 +1,13 @@ + + + + + + + + diff --git a/binaries/org.eclipse.swt.gtk.linux.riscv64/.settings/.api_filters b/binaries/org.eclipse.swt.gtk.linux.riscv64/.settings/.api_filters index 8e2bada0988..aaf1211d52e 100644 --- a/binaries/org.eclipse.swt.gtk.linux.riscv64/.settings/.api_filters +++ b/binaries/org.eclipse.swt.gtk.linux.riscv64/.settings/.api_filters @@ -1,5 +1,13 @@ + + + + + + + + diff --git a/binaries/org.eclipse.swt.gtk.linux.x86_64/.settings/.api_filters b/binaries/org.eclipse.swt.gtk.linux.x86_64/.settings/.api_filters index 75d51ab81da..e78f14df3fa 100644 --- a/binaries/org.eclipse.swt.gtk.linux.x86_64/.settings/.api_filters +++ b/binaries/org.eclipse.swt.gtk.linux.x86_64/.settings/.api_filters @@ -1,5 +1,13 @@ + + + + + + + + diff --git a/binaries/org.eclipse.swt.win32.win32.aarch64/.settings/.api_filters b/binaries/org.eclipse.swt.win32.win32.aarch64/.settings/.api_filters index 5d9b337405d..f64499e9c77 100644 --- a/binaries/org.eclipse.swt.win32.win32.aarch64/.settings/.api_filters +++ b/binaries/org.eclipse.swt.win32.win32.aarch64/.settings/.api_filters @@ -1,5 +1,13 @@ + + + + + + + + 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 5e3408929c5..32502237881 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 @@ -1,5 +1,13 @@ + + + + + + + + diff --git a/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/AnimatedProgress.java b/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/AnimatedProgress.java index bfada002362..ba28078c712 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/AnimatedProgress.java +++ b/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/AnimatedProgress.java @@ -209,9 +209,9 @@ public synchronized void start() { final Runnable [] timer = new Runnable [1]; timer [0] = () -> { if (!active) return; - GC gc = new GC(AnimatedProgress.this); - paintStripes(gc); - gc.dispose(); + try (var gc = GC.create(AnimatedProgress.this)) { + paintStripes(gc); + } display.timerExec (SLEEP, timer [0]); }; display.timerExec (SLEEP, timer [0]); diff --git a/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/CLabel.java b/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/CLabel.java index 71e0b30795d..b4ad2894e5d 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/CLabel.java +++ b/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/CLabel.java @@ -270,16 +270,17 @@ private Point getTotalSize(Image image, String text) { size.y += r.height; } - GC gc = new GC(this); - if (text != null && text.length() > 0) { - Point e = gc.textExtent(text, DRAW_FLAGS); - size.x += e.x; - size.y = Math.max(size.y, e.y); - if (image != null) size.x += GAP; - } else { - size.y = Math.max(size.y, gc.getFontMetrics().getHeight()); + try (var gc = GC.create(this)) { + if (text != null && text.length() > 0) { + Point e = gc.textExtent(text, DRAW_FLAGS); + size.x += e.x; + size.y = Math.max(size.y, e.y); + if (image != null) + size.x += GAP; + } else { + size.y = Math.max(size.y, gc.getFontMetrics().getHeight()); + } } - gc.dispose(); return size; } 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 d35d799bb0f..352e536224a 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 @@ -3835,42 +3835,25 @@ boolean updateItems() { } boolean updateItems (int showIndex) { - GC gc = new GC(this); - if (!single && !mru && showIndex != -1) { - // make sure selected item will be showing - int firstIndex = showIndex; - if (priority[0] < showIndex) { - int maxWidth = getRightItemEdge(gc) - getLeftItemEdge(gc, CTabFolderRenderer.PART_BORDER); - int width = 0; - int[] widths = new int[items.length]; - for (int i = priority[0]; i <= showIndex; i++) { - int state = CTabFolderRenderer.MINIMUM_SIZE; - if (i == selectedIndex) state |= SWT.SELECTED; - widths[i] = renderer.computeSize(i, state, gc, SWT.DEFAULT, SWT.DEFAULT).x; - width += widths[i]; - if (width > maxWidth) break; - } - if (width > maxWidth) { - width = 0; - for (int i = showIndex; i >= 0; i--) { - int state = CTabFolderRenderer.MINIMUM_SIZE; - if (i == selectedIndex) state |= SWT.SELECTED; - if (widths[i] == 0) widths[i] = renderer.computeSize(i, state, gc, SWT.DEFAULT, SWT.DEFAULT).x; - width += widths[i]; - if (width > maxWidth) break; - firstIndex = i; - } - } else { - firstIndex = priority[0]; - for (int i = showIndex + 1; i < items.length; i++) { + boolean changed = false; + try(var gc = GC.create(this)) { + if (!single && !mru && showIndex != -1) { + // make sure selected item will be showing + int firstIndex = showIndex; + if (priority[0] < showIndex) { + int maxWidth = getRightItemEdge(gc) - getLeftItemEdge(gc, CTabFolderRenderer.PART_BORDER); + int width = 0; + int[] widths = new int[items.length]; + for (int i = priority[0]; i <= showIndex; i++) { int state = CTabFolderRenderer.MINIMUM_SIZE; if (i == selectedIndex) state |= SWT.SELECTED; widths[i] = renderer.computeSize(i, state, gc, SWT.DEFAULT, SWT.DEFAULT).x; width += widths[i]; - if (width >= maxWidth) break; + if (width > maxWidth) break; } - if (width < maxWidth) { - for (int i = priority[0] - 1; i >= 0; i--) { + if (width > maxWidth) { + width = 0; + for (int i = showIndex; i >= 0; i--) { int state = CTabFolderRenderer.MINIMUM_SIZE; if (i == selectedIndex) state |= SWT.SELECTED; if (widths[i] == 0) widths[i] = renderer.computeSize(i, state, gc, SWT.DEFAULT, SWT.DEFAULT).x; @@ -3878,50 +3861,68 @@ boolean updateItems (int showIndex) { if (width > maxWidth) break; firstIndex = i; } + } else { + firstIndex = priority[0]; + for (int i = showIndex + 1; i < items.length; i++) { + int state = CTabFolderRenderer.MINIMUM_SIZE; + if (i == selectedIndex) state |= SWT.SELECTED; + widths[i] = renderer.computeSize(i, state, gc, SWT.DEFAULT, SWT.DEFAULT).x; + width += widths[i]; + if (width >= maxWidth) break; + } + if (width < maxWidth) { + for (int i = priority[0] - 1; i >= 0; i--) { + int state = CTabFolderRenderer.MINIMUM_SIZE; + if (i == selectedIndex) state |= SWT.SELECTED; + if (widths[i] == 0) widths[i] = renderer.computeSize(i, state, gc, SWT.DEFAULT, SWT.DEFAULT).x; + width += widths[i]; + if (width > maxWidth) break; + firstIndex = i; + } + } } - } - } - if (firstIndex != priority[0]) { - int index = 0; - // enumerate tabs from first visible to the last existing one (sorted ascending) - for (int i = firstIndex; i < items.length; i++) { - priority[index++] = i; } - // enumerate hidden tabs on the left hand from first visible one - // in the inverse order (sorted descending) so that the originally - // first opened tab is always at the end of the list - for (int i = firstIndex - 1; i >= 0; i--) { - priority[index++] = i; + if (firstIndex != priority[0]) { + int index = 0; + // enumerate tabs from first visible to the last existing one (sorted ascending) + for (int i = firstIndex; i < items.length; i++) { + priority[index++] = i; + } + // enumerate hidden tabs on the left hand from first visible one + // in the inverse order (sorted descending) so that the originally + // first opened tab is always at the end of the list + for (int i = firstIndex - 1; i >= 0; i--) { + priority[index++] = i; + } } } - } - boolean oldShowChevron = showChevron; - boolean changed = setItemSize(gc); - updateButtons(); - boolean chevronChanged = showChevron != oldShowChevron; - if (chevronChanged) { - if (updateTabHeight(false)) { - // Tab height has changed. Item sizes have to be set again. - changed |= setItemSize(gc); + boolean oldShowChevron = showChevron; + changed = setItemSize(gc); + updateButtons(); + boolean chevronChanged = showChevron != oldShowChevron; + if (chevronChanged) { + if (updateTabHeight(false)) { + // Tab height has changed. Item sizes have to be set again. + changed |= setItemSize(gc); + } + } + changed |= setItemLocation(gc); + setButtonBounds(); + changed |= chevronChanged; + if (changed && getToolTipText() != null) { + Point pt = toControl(getDisplay().getCursorLocation()); + _setToolTipText(pt.x, pt.y); } } - changed |= setItemLocation(gc); - setButtonBounds(); - changed |= chevronChanged; - if (changed && getToolTipText() != null) { - Point pt = toControl(getDisplay().getCursorLocation()); - _setToolTipText(pt.x, pt.y); - } - gc.dispose(); return changed; } boolean updateTabHeight(boolean force){ int oldHeight = tabHeight; - GC gc = new GC(this); - tabHeight = renderer.computeSize(CTabFolderRenderer.PART_HEADER, SWT.NONE, gc, SWT.DEFAULT, SWT.DEFAULT).y; - gc.dispose(); + try(var gc = GC.create(this)) { + tabHeight = renderer.computeSize(CTabFolderRenderer.PART_HEADER, SWT.NONE, gc, SWT.DEFAULT, SWT.DEFAULT).y; + } if (fixedTabHeight == SWT.DEFAULT && controls != null && controls.length > 0) { for (int i = 0; i < controls.length; i++) { if ((controlAlignments[i] & SWT.WRAP) == 0 && !controls[i].isDisposed() && controls[i].getVisible()) { diff --git a/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/StyledTextRenderer.java b/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/StyledTextRenderer.java index fa0281c2b31..c4b938847fd 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/StyledTextRenderer.java +++ b/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/StyledTextRenderer.java @@ -1500,10 +1500,10 @@ void setFont(Font font, int tabs) { tabWidth = layout.getBounds().width; layout.dispose(); if (styledText != null) { - GC gc = new GC(styledText); - averageCharWidth = (int) gc.getFontMetrics().getAverageCharacterWidth(); - fixedPitch = gc.stringExtent("l").x == gc.stringExtent("W").x; //$NON-NLS-1$ //$NON-NLS-2$ - gc.dispose(); + try (var gc = GC.create(styledText)) { + averageCharWidth = (int) gc.getFontMetrics().getAverageCharacterWidth(); + fixedPitch = gc.stringExtent("l").x == gc.stringExtent("W").x; //$NON-NLS-1$ //$NON-NLS-2$ + } } } void setLineAlignment(int startLine, int count, int alignment) { diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/AutoDisposableGC.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/AutoDisposableGC.java new file mode 100644 index 00000000000..f6df98179b4 --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/AutoDisposableGC.java @@ -0,0 +1,18 @@ +package org.eclipse.swt.graphics; + +/** + * An AutoCloseable implementation of GC which calls dispose in the close + * method. Can be created via {@link GC#create(Drawable)}. + * + * @since 3.133 + */ +public final class AutoDisposableGC extends GC implements AutoCloseable { + + AutoDisposableGC(Drawable drawable, int style) { + super(drawable, style); + } + @Override + public void close() { + dispose(); + } +} \ No newline at end of file diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/GC.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/GC.java index aa4818e9c19..1783875b5d2 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/GC.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/GC.java @@ -59,7 +59,8 @@ * @see SWT Examples: GraphicsExample, PaintExample * @see Sample code and further information */ -public final class GC extends Resource { +public sealed class GC extends Resource permits AutoDisposableGC { + /** * the handle to the OS device context * (Warning: This field is platform dependent) @@ -207,7 +208,9 @@ public void draw(int x, int y) { * foreground color, background color and font in the GC * to match those in the drawable. *

- * You must dispose the graphics context when it is no longer required. + * You must dispose the graphics context when it is no longer required or + * create a safe context via {@link #create(Drawable)} which takes over + * disposal when called in a try-with-resources statement. *

* @param drawable the drawable to draw on * @exception IllegalArgumentException
    @@ -234,7 +237,9 @@ public GC(Drawable drawable) { * foreground color, background color and font in the GC * to match those in the drawable. *

    - * You must dispose the graphics context when it is no longer required. + * You must dispose the graphics context when it is no longer required or + * create a safe context via {@link #create(Drawable)} which takes over + * disposal when called in a try-with-resources statement. *

    * * @param drawable the drawable to draw on @@ -276,6 +281,19 @@ public GC(Drawable drawable, int style) { } } +/** + * Creates an AutoCloseable instance of the GC class which has been configured + * to draw on the specified drawable. GC.dispose() will be called automatically + * in the close() method if called in a try-with-resources statement. + * + * @since 3.133 + * @param drawable the drawable to draw on + * @return AutoDisposableGC + */ +public static AutoDisposableGC create(Drawable drawable) { + return new AutoDisposableGC(drawable, SWT.NONE); +} + static int checkStyle (int style) { if ((style & SWT.LEFT_TO_RIGHT) != 0) style &= ~SWT.RIGHT_TO_LEFT; return style & (SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT); 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 efc5d4f3b1b..ad48bfd3d66 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 @@ -280,9 +280,9 @@ void init(NSImageRep nativeRep, NSBitmapImageRep rep) { * as shown in the following example: *
      *    Image i = new Image(device, width, height);
    - *    GC gc = new GC(i);
    - *    gc.drawRectangle(0, 0, 50, 50);
    - *    gc.dispose();
    + *    try (var gc = GC.create(i)) {
    + *      gc.drawRectangle(0, 0, 50, 50));
    + *    }
      * 
    *

    * Note: Some platforms may have a limitation on the size @@ -502,9 +502,9 @@ private void createRepFromSourceAndApplyFlag(NSBitmapImageRep srcRep, int srcWid * drawing operations, as shown in the following example: *

      *    Image i = new Image(device, boundsRectangle);
    - *    GC gc = new GC(i);
    - *    gc.drawRectangle(0, 0, 50, 50);
    - *    gc.dispose();
    + *    try (var gc = GC.create(i)) {
    + *      gc.drawRectangle(0, 0, 50, 50);
    + *    }
      * 
    *

    * Note: Some platforms may have a limitation on the size diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/graphics/AutoDisposableGC.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/graphics/AutoDisposableGC.java new file mode 100644 index 00000000000..f6df98179b4 --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/graphics/AutoDisposableGC.java @@ -0,0 +1,18 @@ +package org.eclipse.swt.graphics; + +/** + * An AutoCloseable implementation of GC which calls dispose in the close + * method. Can be created via {@link GC#create(Drawable)}. + * + * @since 3.133 + */ +public final class AutoDisposableGC extends GC implements AutoCloseable { + + AutoDisposableGC(Drawable drawable, int style) { + super(drawable, style); + } + @Override + public void close() { + dispose(); + } +} \ No newline at end of file diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/graphics/GC.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/graphics/GC.java index 6ba1ee1cea7..6e15d4fd6ea 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/graphics/GC.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/graphics/GC.java @@ -60,7 +60,8 @@ * @see SWT Examples: GraphicsExample, PaintExample * @see Sample code and further information */ -public final class GC extends Resource { +public sealed class GC extends Resource permits AutoDisposableGC { + /** * the handle to the OS device context * (Warning: This field is platform dependent) @@ -126,7 +127,9 @@ public final class GC extends Resource { * foreground color, background color and font in the GC * to match those in the drawable. *

    - * You must dispose the graphics context when it is no longer required. + * You must dispose the graphics context when it is no longer required or + * create a safe context via {@link #create(Drawable)} which takes over + * disposal when called in a try-with-resources statement. *

    * @param drawable the drawable to draw on * @exception IllegalArgumentException
      @@ -153,7 +156,9 @@ public GC(Drawable drawable) { * foreground color, background color and font in the GC * to match those in the drawable. *

      - * You must dispose the graphics context when it is no longer required. + * You must dispose the graphics context when it is no longer required or + * create a safe context via {@link #create(Drawable)} which takes over + * disposal when called in a try-with-resources statement. *

      * * @param drawable the drawable to draw on @@ -190,6 +195,19 @@ public GC(Drawable drawable, int style) { init(); } +/** + * Creates an AutoCloseable instance of the GC class which has been configured + * to draw on the specified drawable. GC.dispose() will be called automatically + * in the close() method if called in a try-with-resources statement. + * + * @since 3.133 + * @param drawable the drawable to draw on + * @return AutoDisposableGC + */ +public static AutoDisposableGC create(Drawable drawable) { + return new AutoDisposableGC(drawable, SWT.NONE); +} + /** * Ensure that the style specified is either LEFT_TO_RIGHT or RIGHT_TO_LEFT. * 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 8e08a3cd97c..ce021624a45 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 @@ -185,9 +185,9 @@ public final class Image extends Resource implements Drawable { * as shown in the following example: *
        *    Image i = new Image(device, width, height);
      - *    GC gc = new GC(i);
      - *    gc.drawRectangle(0, 0, 50, 50);
      - *    gc.dispose();
      + *    try (var gc = GC.create(i)) {
      + *      gc.drawRectangle(0, 0, 50, 50));
      + *    }
        * 
      *

      * Note: Some platforms may have a limitation on the size @@ -378,9 +378,9 @@ public Image(Device device, Image srcImage, int flag) { * drawing operations, as shown in the following example: *

        *    Image i = new Image(device, boundsRectangle);
      - *    GC gc = new GC(i);
      - *    gc.drawRectangle(0, 0, 50, 50);
      - *    gc.dispose();
      + *    try (var gc = GC.create(i)) {
      + *      gc.drawRectangle(0, 0, 50, 50);
      + *    }
        * 
      *

      * Note: Some platforms may have a limitation on the size diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/AutoDisposableGC.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/AutoDisposableGC.java new file mode 100644 index 00000000000..f6df98179b4 --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/AutoDisposableGC.java @@ -0,0 +1,18 @@ +package org.eclipse.swt.graphics; + +/** + * An AutoCloseable implementation of GC which calls dispose in the close + * method. Can be created via {@link GC#create(Drawable)}. + * + * @since 3.133 + */ +public final class AutoDisposableGC extends GC implements AutoCloseable { + + AutoDisposableGC(Drawable drawable, int style) { + super(drawable, style); + } + @Override + public void close() { + dispose(); + } +} \ No newline at end of file diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/GC.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/GC.java index 59d1cd0de9f..04353fdbf92 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/GC.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/GC.java @@ -63,7 +63,7 @@ * @see SWT Examples: GraphicsExample, PaintExample * @see Sample code and further information */ -public final class GC extends Resource { +public sealed class GC extends Resource permits AutoDisposableGC { /** * the handle to the OS device context @@ -121,7 +121,9 @@ public final class GC extends Resource { * foreground color, background color and font in the GC * to match those in the drawable. *

      - * You must dispose the graphics context when it is no longer required. + * You must dispose the graphics context when it is no longer required or + * create a safe context via {@link #create(Drawable)} which takes over + * disposal when called in a try-with-resources statement. *

      * @param drawable the drawable to draw on * @exception IllegalArgumentException
        @@ -148,7 +150,9 @@ public GC(Drawable drawable) { * foreground color, background color and font in the GC * to match those in the drawable. *

        - * You must dispose the graphics context when it is no longer required. + * You must dispose the graphics context when it is no longer required or + * create a safe context via {@link #create(Drawable)} which takes over + * disposal when called in a try-with-resources statement. *

        * * @param drawable the drawable to draw on @@ -185,6 +189,19 @@ public GC(Drawable drawable, int style) { init(); } +/** + * Creates an AutoCloseable instance of the GC class which has been configured + * to draw on the specified drawable. GC.dispose() will be called automatically + * in the close() method if called in a try-with-resources statement. + * + * @since 3.133 + * @param drawable the drawable to draw on + * @return AutoDisposableGC + */ +public static AutoDisposableGC create(Drawable drawable) { + return new AutoDisposableGC(drawable, SWT.NONE); +} + static int checkStyle(int style) { if ((style & SWT.LEFT_TO_RIGHT) != 0) style &= ~SWT.RIGHT_TO_LEFT; return style & (SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT); 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 7abf910b88e..1df7217950b 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 @@ -276,9 +276,9 @@ private Image (Device device, int type, long handle, int nativeZoom) { * as shown in the following example: *
          *    Image i = new Image(device, width, height);
        - *    GC gc = new GC(i);
        - *    gc.drawRectangle(0, 0, 50, 50);
        - *    gc.dispose();
        + *    try (var gc = GC.create(i)) {
        + *      gc.drawRectangle(0, 0, 50, 50));
        + *    }
          * 
        *

        * Note: Some platforms may have a limitation on the size @@ -436,9 +436,9 @@ public Image(Device device, Image srcImage, int flag) { * drawing operations, as shown in the following example: *

          *    Image i = new Image(device, boundsRectangle);
        - *    GC gc = new GC(i);
        - *    gc.drawRectangle(0, 0, 50, 50);
        - *    gc.dispose();
        + *    try (var gc = GC.create(i)) {
        + *      gc.drawRectangle(0, 0, 50, 50);
        + *    }
          * 
        *

        * Note: Some platforms may have a limitation on the size