Skip to content

Commit d72a940

Browse files
akoch-yattafedejeanne
authored andcommitted
[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 eclipse-platform#2246
1 parent edc5529 commit d72a940

File tree

3 files changed

+94
-46
lines changed

3 files changed

+94
-46
lines changed

bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/win32/org/eclipse/swt/dnd/DropTarget.java

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -242,29 +242,35 @@ void createCOMInterfaces() {
242242
public long method2(long[] args) {return Release();}
243243
@Override
244244
public long method3(long[] args) {
245-
if (args.length == 5) {
246-
return DragEnter(args[0], (int)args[1], (int)args[2], (int)args[3], args[4]);
247-
} else {
248-
return DragEnter_64(args[0], (int)args[1], args[2], args[3]);
249-
}
245+
return Win32DPIUtils.runWithProperDPIAwareness(() -> {
246+
if (args.length == 5) {
247+
return DragEnter(args[0], (int)args[1], (int)args[2], (int)args[3], args[4]);
248+
} else {
249+
return DragEnter_64(args[0], (int)args[1], args[2], args[3]);
250+
}
251+
});
250252
}
251253
@Override
252254
public long method4(long[] args) {
253-
if (args.length == 4) {
254-
return DragOver((int)args[0], (int)args[1], (int)args[2], args[3]);
255-
} else {
256-
return DragOver_64((int)args[0], args[1], args[2]);
257-
}
255+
return Win32DPIUtils.runWithProperDPIAwareness(() -> {
256+
if (args.length == 4) {
257+
return DragOver((int)args[0], (int)args[1], (int)args[2], args[3]);
258+
} else {
259+
return DragOver_64((int)args[0], args[1], args[2]);
260+
}
261+
});
258262
}
259263
@Override
260264
public long method5(long[] args) {return DragLeave();}
261265
@Override
262266
public long method6(long[] args) {
263-
if (args.length == 5) {
264-
return Drop(args[0], (int)args[1], (int)args[2], (int)args[3], args[4]);
265-
} else {
266-
return Drop_64(args[0], (int)args[1], args[2], args[3]);
267-
}
267+
return Win32DPIUtils.runWithProperDPIAwareness(() -> {
268+
if (args.length == 5) {
269+
return Drop(args[0], (int)args[1], (int)args[2], (int)args[3], args[4]);
270+
} else {
271+
return Drop_64(args[0], (int)args[1], args[2], args[3]);
272+
}
273+
});
268274
}
269275
};
270276
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2025 Yatta Solutions and others.
3+
*
4+
* This program and the accompanying materials
5+
* are made available under the terms of the Eclipse Public License 2.0
6+
* which accompanies this distribution, and is available at
7+
* https://www.eclipse.org/legal/epl-2.0/
8+
*
9+
* SPDX-License-Identifier: EPL-2.0
10+
*
11+
* Contributors:
12+
* Yatta Solutions - initial API and implementation
13+
*******************************************************************************/
14+
package org.eclipse.swt.internal;
15+
16+
import java.util.function.*;
17+
18+
import org.eclipse.swt.internal.win32.*;
19+
import org.eclipse.swt.internal.win32.version.*;
20+
21+
/**
22+
* This class is used in the win32 implementation only to provide
23+
* DPI related utility methods.
24+
* <p>
25+
* <b>IMPORTANT:</b> This class is <em>not</em> part of the public
26+
* API for SWT. It is marked public only so that it can be shared
27+
* within the packages provided by SWT. It is not available on all
28+
* platforms, and should never be called from application code.
29+
* </p>
30+
* @noreference This class is not intended to be referenced by clients
31+
*/
32+
public class Win32DPIUtils {
33+
public static boolean setDPIAwareness(int desiredDpiAwareness) {
34+
if (desiredDpiAwareness == OS.GetThreadDpiAwarenessContext()) {
35+
return true;
36+
}
37+
if (desiredDpiAwareness == OS.DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2) {
38+
// "Per Monitor V2" only available in more recent Windows version
39+
boolean perMonitorV2Available = OsVersion.IS_WIN10_1809;
40+
if (!perMonitorV2Available) {
41+
System.err.println("***WARNING: the OS version does not support DPI awareness mode PerMonitorV2.");
42+
return false;
43+
}
44+
}
45+
long setDpiAwarenessResult = OS.SetThreadDpiAwarenessContext(desiredDpiAwareness);
46+
if (setDpiAwarenessResult == 0L) {
47+
System.err.println("***WARNING: setting DPI awareness failed.");
48+
return false;
49+
}
50+
return true;
51+
}
52+
53+
public static <T> T runWithProperDPIAwareness(Supplier<T> operation) {
54+
// refreshing is only necessary, when monitor specific scaling is active
55+
long previousDPIAwareness = OS.GetThreadDpiAwarenessContext();
56+
try {
57+
if (!setDPIAwareness(OS.DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2)) {
58+
// awareness was not changed, so no need to reset it
59+
previousDPIAwareness = 0;
60+
}
61+
return operation.get();
62+
} finally {
63+
if (previousDPIAwareness > 0) {
64+
OS.SetThreadDpiAwarenessContext(previousDPIAwareness);
65+
}
66+
}
67+
}
68+
}

bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Display.java

Lines changed: 5 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -5404,7 +5404,7 @@ public boolean setRescalingAtRuntime(boolean activate) {
54045404

54055405
private boolean setMonitorSpecificScaling(boolean activate) {
54065406
int desiredApiAwareness = activate ? OS.DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 : OS.DPI_AWARENESS_CONTEXT_SYSTEM_AWARE;
5407-
if (setDPIAwareness(desiredApiAwareness)) {
5407+
if (Win32DPIUtils.setDPIAwareness(desiredApiAwareness)) {
54085408
rescalingAtRuntime = activate;
54095409
coordinateSystemMapper = activate ? new MultiZoomCoordinateSystemMapper(this, this::getMonitors) : new SingleZoomCoordinateSystemMapper(this);
54105410
// dispose a existing font registry for the default display
@@ -5414,38 +5414,12 @@ private boolean setMonitorSpecificScaling(boolean activate) {
54145414
return false;
54155415
}
54165416

5417-
private boolean setDPIAwareness(int desiredDpiAwareness) {
5418-
if (desiredDpiAwareness == OS.GetThreadDpiAwarenessContext()) {
5419-
return true;
5420-
}
5421-
if (desiredDpiAwareness == OS.DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2) {
5422-
// "Per Monitor V2" only available in more recent Windows version
5423-
boolean perMonitorV2Available = OsVersion.IS_WIN10_1809;
5424-
if (!perMonitorV2Available) {
5425-
System.err.println("***WARNING: the OS version does not support DPI awareness mode PerMonitorV2.");
5426-
return false;
5427-
}
5428-
}
5429-
long setDpiAwarenessResult = OS.SetThreadDpiAwarenessContext(desiredDpiAwareness);
5430-
if (setDpiAwarenessResult == 0L) {
5431-
System.err.println("***WARNING: setting DPI awareness failed.");
5432-
return false;
5433-
}
5434-
return true;
5435-
}
5436-
54375417
private void runWithProperDPIAwareness(Runnable operation) {
54385418
if (isRescalingAtRuntime()) {
5439-
// refreshing is only necessary, when monitor specific scaling is active
5440-
long previousDPIAwareness = OS.GetThreadDpiAwarenessContext();
5441-
if (!setDPIAwareness(OS.DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2)) {
5442-
// awareness was not changed, so no need to reset it
5443-
previousDPIAwareness = 0;
5444-
}
5445-
operation.run();
5446-
if (previousDPIAwareness > 0) {
5447-
OS.SetThreadDpiAwarenessContext(previousDPIAwareness);
5448-
}
5419+
Win32DPIUtils.runWithProperDPIAwareness(() -> {
5420+
operation.run();
5421+
return true;
5422+
});
54495423
} else {
54505424
operation.run();
54515425
}

0 commit comments

Comments
 (0)