Skip to content

Commit

Permalink
Destroy unused handles of resources
Browse files Browse the repository at this point in the history
This Contribution destroys those handles for the resources which were
created for zoom levels which no monitor has anymore. The process is
triggered on a DPI_CHANGED event.

contributes to #62 and eclipse-platform#127
  • Loading branch information
amartya4256 authored and fedejeanne committed Oct 15, 2024
1 parent 30f11e9 commit f5e534a
Show file tree
Hide file tree
Showing 8 changed files with 145 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
*******************************************************************************/
package org.eclipse.swt.graphics;

import java.util.*;
import java.util.function.*;

import org.eclipse.swt.*;
Expand Down Expand Up @@ -123,6 +124,17 @@ public Resource() {
void destroy() {
}

/**
* Destroy all handles of the resource which are not necessary for the given
* zoom levels. This method is supposed to be overridden by sub-classes that
* retain handles for different zoom levels.
*
* @param zoomLevels The zoom levels for which the handles are supposed to be
* retained.
*/
void destroyHandlesExcept(Set<Integer> zoomLevels) {
}

/**
* Disposes of the operating system resources associated with
* this resource. Applications must dispose of all resources
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,14 @@
package org.eclipse.swt.graphics;


import java.util.*;
import java.util.concurrent.*;

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

/**
* This class is the abstract superclass of all device objects,
Expand Down Expand Up @@ -55,6 +59,7 @@ public abstract class Device implements Drawable {
String[] loadedFonts;

volatile boolean disposed;
private Set<Resource> resourcesWithZoomSupport = ConcurrentHashMap.newKeySet();

/*
* TEMPORARY CODE. When a graphics object is
Expand Down Expand Up @@ -914,6 +919,8 @@ protected void release () {
Gdip.GdiplusShutdown (gdipToken[0]);
}
SWTFontProvider.disposeFontRegistry(this);
resourcesWithZoomSupport.clear();
resourcesWithZoomSupport = null;
gdipToken = null;
scripts = null;
logFonts = null;
Expand Down Expand Up @@ -947,4 +954,24 @@ public void setWarnings (boolean warnings) {
protected int getDeviceZoom () {
return DPIUtil.mapDPIToZoom ( _getDPIx ());
}

void registerResourceWithZoomSupport(Resource resource) {
resourcesWithZoomSupport.add(resource);
}

/**
* Destroys the handles of all the resources in the resource tracker by
* identifying the zoom levels which is not valid for any monitor
*
* @noreference This method is not intended to be referenced by clients.
*/
public static void win32_destroyUnusedHandles(Display display) {
Set<Integer> availableZoomLevels = new HashSet<>();
for (Monitor monitor : display.getMonitors()) {
availableZoomLevels.add(DPIUtil.getZoomForAutoscaleProperty(monitor.getZoom()));
}
for (Resource resource: ((Device) display).resourcesWithZoomSupport) {
resource.destroyHandlesExcept(availableZoomLevels);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ public final class Image extends Resource implements Drawable {
Image (Device device) {
super(device);
initialNativeZoom = DPIUtil.getNativeDeviceZoom();
this.device.registerResourceWithZoomSupport(this);
}

/**
Expand Down Expand Up @@ -209,6 +210,7 @@ public Image(Device device, int width, int height) {
height = DPIUtil.scaleUp (height, zoom);
init(width, height);
init();
this.device.registerResourceWithZoomSupport(this);
}

/**
Expand Down Expand Up @@ -311,6 +313,7 @@ public Image(Device device, Image srcImage, int flag) {
SWT.error(SWT.ERROR_INVALID_ARGUMENT);
}
init();
this.device.registerResourceWithZoomSupport(this);
}

/**
Expand Down Expand Up @@ -355,6 +358,7 @@ public Image(Device device, Rectangle bounds) {
bounds = DPIUtil.scaleUp (bounds, getZoom());
init(bounds.width, bounds.height);
init();
this.device.registerResourceWithZoomSupport(this);
}

/**
Expand Down Expand Up @@ -388,6 +392,7 @@ public Image(Device device, ImageData data) {
data = DPIUtil.autoScaleUp(device, this.dataAtBaseZoom);
init(data, getZoom());
init();
this.device.registerResourceWithZoomSupport(this);
}

/**
Expand Down Expand Up @@ -434,6 +439,7 @@ public Image(Device device, ImageData source, ImageData mask) {
mask = ImageData.convertMask(mask);
init(this.device, this, source, mask, getZoom());
init();
this.device.registerResourceWithZoomSupport(this);
}

/**
Expand Down Expand Up @@ -496,6 +502,7 @@ public Image (Device device, InputStream stream) {
ImageData data = DPIUtil.autoScaleUp(device, this.dataAtBaseZoom);
init(data, getZoom());
init();
this.device.registerResourceWithZoomSupport(this);
}

/**
Expand Down Expand Up @@ -538,6 +545,7 @@ public Image (Device device, String filename) {
ImageData data = DPIUtil.autoScaleUp(device, this.dataAtBaseZoom);
init(data, getZoom());
init();
this.device.registerResourceWithZoomSupport(this);
}

/**
Expand Down Expand Up @@ -586,6 +594,7 @@ public Image(Device device, ImageFileNameProvider imageFileNameProvider) {
init(resizedData, getZoom());
}
init();
this.device.registerResourceWithZoomSupport(this);
}

/**
Expand Down Expand Up @@ -625,6 +634,7 @@ public Image(Device device, ImageDataProvider imageDataProvider) {
ImageData resizedData = DPIUtil.scaleImageData(device, data.element(), getZoom(), data.zoom());
init (resizedData, getZoom());
init();
this.device.registerResourceWithZoomSupport(this);
}

private ImageData adaptImageDataIfDisabledOrGray(ImageData data) {
Expand Down Expand Up @@ -1186,16 +1196,32 @@ void destroy () {

private void destroyHandle () {
for (Long handle : zoomLevelToHandle.values()) {
if (type == SWT.ICON) {
OS.DestroyIcon (handle);
} else {
OS.DeleteObject (handle);
}
destroyHandle(handle);
}
zoomLevelToHandle.clear();
handle = 0;
}

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

private void destroyHandle(long handle) {
if (type == SWT.ICON) {
OS.DestroyIcon (handle);
} else {
OS.DeleteObject (handle);
}
}

/**
* Compares the argument to the receiver, and returns true
* if they represent the <em>same</em> object using a class
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ private Path(Device device, int zoom) {
if (handle == 0) SWT.error(SWT.ERROR_NO_HANDLES);
zoomLevelToHandle.put(initialZoom, handle);
init();
this.device.registerResourceWithZoomSupport(this);
}

/**
Expand Down Expand Up @@ -133,6 +134,7 @@ public Path (Device device, Path path, float flatness) {
initialZoom = path.initialZoom;
zoomLevelToHandle.put(initialZoom, handle);
init();
this.device.registerResourceWithZoomSupport(this);
}

/**
Expand Down Expand Up @@ -172,6 +174,7 @@ private Path(Device device, PathData data, int zoom) {
this(device, zoom);
if (data == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
init(data);
this.device.registerResourceWithZoomSupport(this);
}

/**
Expand Down Expand Up @@ -438,6 +441,18 @@ void destroy() {
zoomLevelToHandle.clear();
}

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

/**
* Replaces the first four elements in the parameter with values that
* describe the smallest rectangle that will completely contain the
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ public Pattern(Device device, Image image) {
initialZoom = DPIUtil.getDeviceZoom();
setImageHandle(image, initialZoom);
init();
this.device.registerResourceWithZoomSupport(this);
}

/**
Expand Down Expand Up @@ -183,6 +184,7 @@ public Pattern(Device device, float x1, float y1, float x2, float y2, Color colo
this.image = null;
initialZoom = DPIUtil.getDeviceZoom();
initializeSize(initialZoom);
this.device.registerResourceWithZoomSupport(this);
}

long getHandle(int zoom) {
Expand Down Expand Up @@ -260,21 +262,7 @@ void setImageHandle(Image image, int zoom) {
@Override
void destroy() {
for (long handle: zoomLevelToHandle.values()) {
int type = Gdip.Brush_GetType(handle);
switch (type) {
case Gdip.BrushTypeSolidColor:
Gdip.SolidBrush_delete(handle);
break;
case Gdip.BrushTypeHatchFill:
Gdip.HatchBrush_delete(handle);
break;
case Gdip.BrushTypeLinearGradient:
Gdip.LinearGradientBrush_delete(handle);
break;
case Gdip.BrushTypeTextureFill:
Gdip.TextureBrush_delete(handle);
break;
}
destroyHandle(handle);
}
zoomLevelToHandle.clear();
if (bitmapDestructor != null) {
Expand All @@ -283,6 +271,36 @@ void destroy() {
}
}

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

private void destroyHandle(long handle) {
int type = Gdip.Brush_GetType(handle);
switch (type) {
case Gdip.BrushTypeSolidColor:
Gdip.SolidBrush_delete(handle);
break;
case Gdip.BrushTypeHatchFill:
Gdip.HatchBrush_delete(handle);
break;
case Gdip.BrushTypeLinearGradient:
Gdip.LinearGradientBrush_delete(handle);
break;
case Gdip.BrushTypeTextureFill:
Gdip.TextureBrush_delete(handle);
break;
}
}

/**
* Returns <code>true</code> if the Pattern has been disposed,
* and <code>false</code> otherwise.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ public Region (Device device) {
zoomToHandle.put(initialZoom, handle);
if (handle == 0) SWT.error(SWT.ERROR_NO_HANDLES);
init();
this.device.registerResourceWithZoomSupport(this);
}

/**
Expand Down Expand Up @@ -227,6 +228,18 @@ void destroy () {
operations.clear();
}

@Override
void destroyHandlesExcept(Set<Integer> zoomLevels) {
zoomToHandle.entrySet().removeIf(entry -> {
final Integer zoom = entry.getKey();
if (!zoomLevels.contains(zoom) && zoom != initialZoom) {
OS.DeleteObject(entry.getValue());
return true;
}
return false;
});
}

/**
* Compares the argument to the receiver, and returns true
* if they represent the <em>same</em> object using a class
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ public Transform (Device device, float m11, float m12, float m21, float m22, flo
if (handle == 0) SWT.error(SWT.ERROR_NO_HANDLES);
zoomLevelToHandle.put(initialZoom, handle);
init();
this.device.registerResourceWithZoomSupport(this);
}

static float[] checkTransform(float[] elements) {
Expand All @@ -159,6 +160,18 @@ void destroy() {
zoomLevelToHandle.clear();
}

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

/**
* Fills the parameter with the values of the transformation matrix
* that the receiver represents, in the order {m11, m12, m21, m22, dx, dy}.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4899,6 +4899,7 @@ LRESULT WM_DPICHANGED (long wParam, long lParam) {
// Map DPI to Zoom and compare
int newNativeZoom = DPIUtil.mapDPIToZoom (OS.HIWORD (wParam));
if (getDisplay().isRescalingAtRuntime()) {
Device.win32_destroyUnusedHandles(getDisplay());
int oldNativeZoom = nativeZoom;
if (newNativeZoom != oldNativeZoom) {
DPIUtil.setDeviceZoom (newNativeZoom);
Expand Down

0 comments on commit f5e534a

Please sign in to comment.