From 87fffcc178c046dfb9b37c2d396ef55a5140e940 Mon Sep 17 00:00:00 2001 From: Andreas Koch Date: Tue, 24 Jun 2025 07:50:52 +0200 Subject: [PATCH] [win32] Ensure correct DPI awareness for DnD This commit sets temporarily the DPI awareness of the thread to PerMonitorV2 if necessary, when DnD operations are executed. This is necessary as the process could be started with System Aware DPI mode which is inherited from the native methods related to DnD. fixes https://github.com/eclipse-platform/eclipse.platform.swt/issues/2246 --- .../win32/org/eclipse/swt/dnd/DropTarget.java | 36 ++++++---- .../eclipse/swt/internal/Win32DPIUtils.java | 68 +++++++++++++++++++ .../org/eclipse/swt/widgets/Display.java | 36 ++-------- 3 files changed, 94 insertions(+), 46 deletions(-) create mode 100644 bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/internal/Win32DPIUtils.java diff --git a/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/win32/org/eclipse/swt/dnd/DropTarget.java b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/win32/org/eclipse/swt/dnd/DropTarget.java index 2a804684a87..c3a78447efc 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/win32/org/eclipse/swt/dnd/DropTarget.java +++ b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/win32/org/eclipse/swt/dnd/DropTarget.java @@ -242,29 +242,35 @@ void createCOMInterfaces() { public long method2(long[] args) {return Release();} @Override public long method3(long[] args) { - if (args.length == 5) { - return DragEnter(args[0], (int)args[1], (int)args[2], (int)args[3], args[4]); - } else { - return DragEnter_64(args[0], (int)args[1], args[2], args[3]); - } + return Win32DPIUtils.runWithProperDPIAwareness(() -> { + if (args.length == 5) { + return DragEnter(args[0], (int)args[1], (int)args[2], (int)args[3], args[4]); + } else { + return DragEnter_64(args[0], (int)args[1], args[2], args[3]); + } + }); } @Override public long method4(long[] args) { - if (args.length == 4) { - return DragOver((int)args[0], (int)args[1], (int)args[2], args[3]); - } else { - return DragOver_64((int)args[0], args[1], args[2]); - } + return Win32DPIUtils.runWithProperDPIAwareness(() -> { + if (args.length == 4) { + return DragOver((int)args[0], (int)args[1], (int)args[2], args[3]); + } else { + return DragOver_64((int)args[0], args[1], args[2]); + } + }); } @Override public long method5(long[] args) {return DragLeave();} @Override public long method6(long[] args) { - if (args.length == 5) { - return Drop(args[0], (int)args[1], (int)args[2], (int)args[3], args[4]); - } else { - return Drop_64(args[0], (int)args[1], args[2], args[3]); - } + return Win32DPIUtils.runWithProperDPIAwareness(() -> { + if (args.length == 5) { + return Drop(args[0], (int)args[1], (int)args[2], (int)args[3], args[4]); + } else { + return Drop_64(args[0], (int)args[1], args[2], args[3]); + } + }); } }; } diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/internal/Win32DPIUtils.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/internal/Win32DPIUtils.java new file mode 100644 index 00000000000..89bbb16a9e3 --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/internal/Win32DPIUtils.java @@ -0,0 +1,68 @@ +/******************************************************************************* + * Copyright (c) 2025 Yatta Solutions 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 Solutions - initial API and implementation + *******************************************************************************/ +package org.eclipse.swt.internal; + +import java.util.function.*; + +import org.eclipse.swt.internal.win32.*; +import org.eclipse.swt.internal.win32.version.*; + +/** + * This class is used in the win32 implementation only to provide + * DPI related utility methods. + *

+ * IMPORTANT: This class is not part of the public + * API for SWT. It is marked public only so that it can be shared + * within the packages provided by SWT. It is not available on all + * platforms, and should never be called from application code. + *

+ * @noreference This class is not intended to be referenced by clients + */ +public class Win32DPIUtils { + public static boolean setDPIAwareness(int desiredDpiAwareness) { + if (desiredDpiAwareness == OS.GetThreadDpiAwarenessContext()) { + return true; + } + if (desiredDpiAwareness == OS.DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2) { + // "Per Monitor V2" only available in more recent Windows version + boolean perMonitorV2Available = OsVersion.IS_WIN10_1809; + if (!perMonitorV2Available) { + System.err.println("***WARNING: the OS version does not support DPI awareness mode PerMonitorV2."); + return false; + } + } + long setDpiAwarenessResult = OS.SetThreadDpiAwarenessContext(desiredDpiAwareness); + if (setDpiAwarenessResult == 0L) { + System.err.println("***WARNING: setting DPI awareness failed."); + return false; + } + return true; + } + + public static T runWithProperDPIAwareness(Supplier operation) { + // refreshing is only necessary, when monitor specific scaling is active + long previousDPIAwareness = OS.GetThreadDpiAwarenessContext(); + try { + if (!setDPIAwareness(OS.DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2)) { + // awareness was not changed, so no need to reset it + previousDPIAwareness = 0; + } + return operation.get(); + } finally { + if (previousDPIAwareness > 0) { + OS.SetThreadDpiAwarenessContext(previousDPIAwareness); + } + } + } +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Display.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Display.java index 511fcdfec44..a775cfcb74c 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Display.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Display.java @@ -5404,7 +5404,7 @@ public boolean setRescalingAtRuntime(boolean activate) { private boolean setMonitorSpecificScaling(boolean activate) { int desiredApiAwareness = activate ? OS.DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 : OS.DPI_AWARENESS_CONTEXT_SYSTEM_AWARE; - if (setDPIAwareness(desiredApiAwareness)) { + if (Win32DPIUtils.setDPIAwareness(desiredApiAwareness)) { rescalingAtRuntime = activate; coordinateSystemMapper = activate ? new MultiZoomCoordinateSystemMapper(this, this::getMonitors) : new SingleZoomCoordinateSystemMapper(this); // dispose a existing font registry for the default display @@ -5414,38 +5414,12 @@ private boolean setMonitorSpecificScaling(boolean activate) { return false; } -private boolean setDPIAwareness(int desiredDpiAwareness) { - if (desiredDpiAwareness == OS.GetThreadDpiAwarenessContext()) { - return true; - } - if (desiredDpiAwareness == OS.DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2) { - // "Per Monitor V2" only available in more recent Windows version - boolean perMonitorV2Available = OsVersion.IS_WIN10_1809; - if (!perMonitorV2Available) { - System.err.println("***WARNING: the OS version does not support DPI awareness mode PerMonitorV2."); - return false; - } - } - long setDpiAwarenessResult = OS.SetThreadDpiAwarenessContext(desiredDpiAwareness); - if (setDpiAwarenessResult == 0L) { - System.err.println("***WARNING: setting DPI awareness failed."); - return false; - } - return true; -} - private void runWithProperDPIAwareness(Runnable operation) { if (isRescalingAtRuntime()) { - // refreshing is only necessary, when monitor specific scaling is active - long previousDPIAwareness = OS.GetThreadDpiAwarenessContext(); - if (!setDPIAwareness(OS.DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2)) { - // awareness was not changed, so no need to reset it - previousDPIAwareness = 0; - } - operation.run(); - if (previousDPIAwareness > 0) { - OS.SetThreadDpiAwarenessContext(previousDPIAwareness); - } + Win32DPIUtils.runWithProperDPIAwareness(() -> { + operation.run(); + return true; + }); } else { operation.run(); }