From dba7865c94dc7deff2a378e26fb29e27c04f604d Mon Sep 17 00:00:00 2001 From: Heiko Klare Date: Thu, 16 Oct 2025 18:28:31 +0200 Subject: [PATCH] [Win32] Move DPI change handling from Control to Shell Currently, DPI change handling is implemented in Control. However, according OS events are only created and reasonable at Shell level. This change thus moves the according implementations to the Shell class. It also limits the last queued DPI event storage for cancellation on subsequent events to the Shell class. --- .../org/eclipse/swt/widgets/Control.java | 56 ++----------------- .../win32/org/eclipse/swt/widgets/Shell.java | 56 +++++++++++++++++++ 2 files changed, 60 insertions(+), 52 deletions(-) diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Control.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Control.java index ebda5e5b8ba..87de8b10f1e 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Control.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Control.java @@ -26,7 +26,6 @@ import org.eclipse.swt.graphics.*; import org.eclipse.swt.internal.*; import org.eclipse.swt.internal.gdip.*; -import org.eclipse.swt.internal.ole.win32.*; import org.eclipse.swt.internal.win32.*; import org.eclipse.swt.ole.win32.*; @@ -80,9 +79,6 @@ public abstract class Control extends Widget implements Drawable { int drawCount, foreground, background, backgroundAlpha = 255; boolean autoScaleDisabled = false; - /** Cache for currently processed DPI change event to be able to cancel it if a new one is triggered */ - Event currentDpiChangeEvent; - private static final String DATA_SHELL_ZOOM = "SHELL_ZOOM"; private static final String DATA_AUTOSCALE_DISABLED = "AUTOSCALE_DISABLED"; @@ -5014,20 +5010,6 @@ LRESULT WM_DESTROY (long wParam, long lParam) { return null; } -private void handleMonitorSpecificDpiChange(int newNativeZoom, Rectangle newBoundsInPixels) { - DPIUtil.setDeviceZoom (newNativeZoom); - // Do not process DPI change for child shells asynchronous to avoid relayouting when - // repositioning the child shell to a different monitor upon opening - boolean processDpiChangeAsynchronous = getShell().getParent() == null; - Event zoomChangedEvent = createZoomChangedEvent(newNativeZoom, processDpiChangeAsynchronous); - if (currentDpiChangeEvent != null) { - currentDpiChangeEvent.doit = false; - } - currentDpiChangeEvent = zoomChangedEvent; - notifyListeners(SWT.ZoomChanged, zoomChangedEvent); - this.setBoundsInPixels(newBoundsInPixels.x, newBoundsInPixels.y, newBoundsInPixels.width, newBoundsInPixels.height); -} - Event createZoomChangedEvent(int zoom, boolean asyncExec) { Event event = new Event(); event.type = SWT.ZoomChanged; @@ -5040,38 +5022,12 @@ Event createZoomChangedEvent(int zoom, boolean asyncExec) { return event; } -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()); - RECT rect = new RECT (); - COM.MoveMemory(rect, lParam, RECT.sizeof); - handleMonitorSpecificDpiChange(newNativeZoom, new Rectangle(rect.left, rect.top, rect.right - rect.left, rect.bottom-rect.top)); - return LRESULT.ZERO; - } else { - int newZoom = DPIUtil.getZoomForAutoscaleProperty (newNativeZoom); - int oldZoom = DPIUtil.getZoomForAutoscaleProperty (nativeZoom); - if (newZoom != oldZoom) { - // Throw the DPI change event if zoom value changes - Event event = new Event(); - event.type = SWT.ZoomChanged; - event.widget = this; - event.detail = DPIUtil.getZoomForAutoscaleProperty(newNativeZoom); - event.doit = true; - notifyListeners(SWT.ZoomChanged, event); - return LRESULT.ZERO; - } - } - return LRESULT.ONE; +LRESULT WM_DPICHANGED(long wParam, long lParam) { + return null; } -LRESULT WM_DISPLAYCHANGE (long wParam, long lParam) { - if (getDisplay().isRescalingAtRuntime()) { - Device.win32_destroyUnusedHandles(getDisplay()); - return LRESULT.ZERO; - } - return LRESULT.ONE; +LRESULT WM_DISPLAYCHANGE(long wParam, long lParam) { + return null; } LRESULT WM_DRAWITEM (long wParam, long lParam) { @@ -5980,7 +5936,6 @@ private boolean decrement() { } void sendZoomChangedEvent(Event event, Shell shell) { - this.currentDpiChangeEvent = event; if (event.data instanceof DPIChangeExecution dpiExecData) { dpiExecData.increment(); dpiExecData.process(this, () -> { @@ -5993,9 +5948,6 @@ void sendZoomChangedEvent(Event event, Shell shell) { return; } if (dpiExecData.decrement()) { - if (event == currentDpiChangeEvent) { - currentDpiChangeEvent = null; - } if (event.doit) { shell.WM_SIZE(0, 0); } diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Shell.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Shell.java index bc380d4d38f..5c0b1ee74c6 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Shell.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Shell.java @@ -18,6 +18,7 @@ import org.eclipse.swt.events.*; import org.eclipse.swt.graphics.*; import org.eclipse.swt.internal.*; +import org.eclipse.swt.internal.ole.win32.*; import org.eclipse.swt.internal.win32.*; import org.eclipse.swt.internal.win32.version.*; @@ -150,6 +151,10 @@ public class Shell extends Decorations { DialogProc = lpWndClass.lpfnWndProc; } + /** Cache for currently processed DPI change event to be able to cancel it if a new one is triggered */ + Event lastDpiChangeEvent; + + /** * Constructs a new instance of this class. This is equivalent * to calling Shell((Display) null). @@ -2430,6 +2435,57 @@ LRESULT WM_DESTROY (long wParam, long lParam) { return result; } +@Override +LRESULT WM_DISPLAYCHANGE (long wParam, long lParam) { + if (getDisplay().isRescalingAtRuntime()) { + Device.win32_destroyUnusedHandles(getDisplay()); + return LRESULT.ZERO; + } + return LRESULT.ONE; +} + +@Override +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()); + RECT rect = new RECT (); + COM.MoveMemory(rect, lParam, RECT.sizeof); + Rectangle newBoundsInPixels = new Rectangle(rect.left, rect.top, rect.right - rect.left, rect.bottom-rect.top); + handleMonitorSpecificDpiChange(newNativeZoom, newBoundsInPixels); + return LRESULT.ZERO; + } else { + int newZoom = DPIUtil.getZoomForAutoscaleProperty (newNativeZoom); + int oldZoom = DPIUtil.getZoomForAutoscaleProperty (nativeZoom); + if (newZoom != oldZoom) { + // Throw the DPI change event if zoom value changes + Event event = new Event(); + event.type = SWT.ZoomChanged; + event.widget = this; + event.detail = DPIUtil.getZoomForAutoscaleProperty(newNativeZoom); + event.doit = true; + notifyListeners(SWT.ZoomChanged, event); + return LRESULT.ZERO; + } + } + return LRESULT.ONE; +} + +private void handleMonitorSpecificDpiChange(int newNativeZoom, Rectangle newBoundsInPixels) { + DPIUtil.setDeviceZoom (newNativeZoom); + // Do not process DPI change for child shells asynchronous to avoid relayouting when + // repositioning the child shell to a different monitor upon opening + boolean processDpiChangeAsynchronous = getParent() == null; + Event zoomChangedEvent = createZoomChangedEvent(newNativeZoom, processDpiChangeAsynchronous); + if (lastDpiChangeEvent != null) { + lastDpiChangeEvent.doit = false; + } + lastDpiChangeEvent = zoomChangedEvent; + notifyListeners(SWT.ZoomChanged, zoomChangedEvent); + this.setBoundsInPixels(newBoundsInPixels.x, newBoundsInPixels.y, newBoundsInPixels.width, newBoundsInPixels.height); +} + @Override LRESULT WM_ENTERIDLE (long wParam, long lParam) { LRESULT result = super.WM_ENTERIDLE (wParam, lParam);