Skip to content

Commit db566e0

Browse files
committed
[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 #2246
1 parent f92b752 commit db566e0

File tree

3 files changed

+96
-49
lines changed

3 files changed

+96
-49
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: 7 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1461,7 +1461,7 @@ public Widget findWidget (Widget widget, long id) {
14611461

14621462
long foregroundIdleProc (long code, long wParam, long lParam) {
14631463
if (code >= 0) {
1464-
Runnable processMessages = () -> {
1464+
Supplier<Boolean> processMessages = () -> {
14651465
sendPostExternalEventDispatchEvent ();
14661466
if (runMessagesInIdle) {
14671467
if (runMessagesInMessageProc) {
@@ -1487,6 +1487,7 @@ long foregroundIdleProc (long code, long wParam, long lParam) {
14871487
int flags = OS.PM_NOREMOVE | OS.PM_NOYIELD | OS.PM_QS_INPUT;
14881488
if (!OS.PeekMessage (msg, 0, 0, 0, flags)) wakeThread ();
14891489
sendPreExternalEventDispatchEvent ();
1490+
return true;
14901491
};
14911492
if (!synchronizer.isMessagesEmpty()) {
14921493
// Windows hooks will inherit the thread DPI awareness from
@@ -3482,6 +3483,7 @@ long msgFilterProc (long code, long wParam, long lParam) {
34823483
if (!OS.PeekMessage (msg, 0, 0, 0, flags)) {
34833484
if (runAsyncMessages (false)) wakeThread ();
34843485
}
3486+
return true;
34853487
});
34863488
}
34873489
break;
@@ -5404,7 +5406,7 @@ public boolean setRescalingAtRuntime(boolean activate) {
54045406

54055407
private boolean setMonitorSpecificScaling(boolean activate) {
54065408
int desiredApiAwareness = activate ? OS.DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 : OS.DPI_AWARENESS_CONTEXT_SYSTEM_AWARE;
5407-
if (setDPIAwareness(desiredApiAwareness)) {
5409+
if (Win32DPIUtils.setDPIAwareness(desiredApiAwareness)) {
54085410
rescalingAtRuntime = activate;
54095411
coordinateSystemMapper = activate ? new MultiZoomCoordinateSystemMapper(this, this::getMonitors) : new SingleZoomCoordinateSystemMapper(this);
54105412
// dispose a existing font registry for the default display
@@ -5414,40 +5416,11 @@ private boolean setMonitorSpecificScaling(boolean activate) {
54145416
return false;
54155417
}
54165418

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-
5437-
private void runWithProperDPIAwareness(Runnable operation) {
5419+
private void runWithProperDPIAwareness(Supplier<Boolean> operation) {
54385420
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-
}
5421+
Win32DPIUtils.runWithProperDPIAwareness(operation);
54495422
} else {
5450-
operation.run();
5423+
operation.get();
54515424
}
54525425
}
54535426
}

0 commit comments

Comments
 (0)