Skip to content

Commit b6f92bf

Browse files
[Refactor] Move autoscaling methods in AutoScaling class
A new utility solely responsible for taking care of autoscaling methods. Also introduced new system property swt.autoScale.force that can be set to true in order to disable the compatibility error for setting the autoscale value when update on runtime is enabled.
1 parent 485749a commit b6f92bf

File tree

9 files changed

+176
-129
lines changed

9 files changed

+176
-129
lines changed

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,7 @@ void createCOMInterfaces() {
242242
public long method2(long[] args) {return Release();}
243243
@Override
244244
public long method3(long[] args) {
245-
return Win32DPIUtils.runWithProperDPIAwareness(getDisplay(), () -> {
245+
return AutoScaling.runWithProperDPIAwareness(getDisplay(), () -> {
246246
if (args.length == 5) {
247247
return DragEnter(args[0], (int)args[1], (int)args[2], (int)args[3], args[4]);
248248
} else {
@@ -252,7 +252,7 @@ public long method3(long[] args) {
252252
}
253253
@Override
254254
public long method4(long[] args) {
255-
return Win32DPIUtils.runWithProperDPIAwareness(getDisplay(), () -> {
255+
return AutoScaling.runWithProperDPIAwareness(getDisplay(), () -> {
256256
if (args.length == 4) {
257257
return DragOver((int)args[0], (int)args[1], (int)args[2], args[3]);
258258
} else {
@@ -264,7 +264,7 @@ public long method4(long[] args) {
264264
public long method5(long[] args) {return DragLeave();}
265265
@Override
266266
public long method6(long[] args) {
267-
return Win32DPIUtils.runWithProperDPIAwareness(getDisplay(), () -> {
267+
return AutoScaling.runWithProperDPIAwareness(getDisplay(), () -> {
268268
if (args.length == 5) {
269269
return Drop(args[0], (int)args[1], (int)args[2], (int)args[3], args[4]);
270270
} else {

bundles/org.eclipse.swt/Eclipse SWT Tests/win32/org/eclipse/swt/internal/ResetMonitorSpecificScalingExtension.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
*******************************************************************************/
1111
package org.eclipse.swt.internal;
1212

13+
import org.eclipse.swt.*;
1314
import org.eclipse.swt.widgets.*;
1415
import org.junit.jupiter.api.extension.*;
1516

@@ -25,13 +26,13 @@ protected ResetMonitorSpecificScalingExtension() {
2526

2627
@Override
2728
public void beforeEach(ExtensionContext context) throws Exception {
28-
wasMonitorSpecificScalingActive = Win32DPIUtils.isMonitorSpecificScalingActive();
29+
wasMonitorSpecificScalingActive = AutoScaling.isMonitorSpecificScalingActive();
2930
Display.getDefault().dispose();
3031
}
3132

3233
@Override
3334
public void afterEach(ExtensionContext context) throws Exception {
34-
Win32DPIUtils.setMonitorSpecificScaling(wasMonitorSpecificScalingActive);
35+
AutoScaling.setMonitorSpecificScaling(wasMonitorSpecificScalingActive);
3536
Display.getDefault().dispose();
3637
DPIUtil.setDeviceZoom(100);
3738
}

bundles/org.eclipse.swt/Eclipse SWT Tests/win32/org/eclipse/swt/internal/WithMonitorSpecificScalingExtension.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
*******************************************************************************/
1111
package org.eclipse.swt.internal;
1212

13+
import org.eclipse.swt.*;
1314
import org.junit.jupiter.api.extension.*;
1415

1516
/**
@@ -24,7 +25,7 @@ private WithMonitorSpecificScalingExtension() {
2425
@Override
2526
public void beforeEach(ExtensionContext context) throws Exception {
2627
super.beforeEach(context);
27-
Win32DPIUtils.setMonitorSpecificScaling(true);
28+
AutoScaling.setMonitorSpecificScaling(true);
2829
}
2930

3031
}

bundles/org.eclipse.swt/Eclipse SWT Tests/win32/org/eclipse/swt/widgets/ControlWin32Tests.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ class ControlWin32Tests {
3636

3737
@Test
3838
public void testScaleFontCorrectlyInAutoScaleScenario() {
39-
Win32DPIUtils.setMonitorSpecificScaling(true);
39+
AutoScaling.setMonitorSpecificScaling(true);
4040
Display display = Display.getDefault();
4141

4242
assertTrue("Autoscale property is not set to true", display.isRescalingAtRuntime());
@@ -48,7 +48,7 @@ public void testScaleFontCorrectlyInAutoScaleScenario() {
4848

4949
@Test
5050
public void testSetFontWithMonitorSpecificScalingEnabled() {
51-
Win32DPIUtils.setMonitorSpecificScaling(true);
51+
AutoScaling.setMonitorSpecificScaling(true);
5252
Display display = Display.getDefault();
5353
Image colorImage = new Image(display, 10, 10);
5454
GC gc = new GC(colorImage);
@@ -59,7 +59,7 @@ public void testSetFontWithMonitorSpecificScalingEnabled() {
5959

6060
@Test
6161
public void testDoNotScaleFontInNoAutoScaleScenario() {
62-
Win32DPIUtils.setMonitorSpecificScaling(false);
62+
AutoScaling.setMonitorSpecificScaling(false);
6363
Display display = Display.getDefault();
6464

6565
assertFalse("Autoscale property is not set to false", display.isRescalingAtRuntime());
@@ -71,7 +71,7 @@ public void testDoNotScaleFontInNoAutoScaleScenario() {
7171

7272
@Test
7373
public void testDoNotScaleFontInNoAutoScaleScenarioWithLegacyFontRegistry() {
74-
Win32DPIUtils.setMonitorSpecificScaling(false);
74+
AutoScaling.setMonitorSpecificScaling(false);
7575
String originalValue = System.getProperty("swt.fontRegistry");
7676
System.setProperty("swt.fontRegistry", "legacy");
7777
try {
@@ -93,7 +93,7 @@ public void testDoNotScaleFontInNoAutoScaleScenarioWithLegacyFontRegistry() {
9393

9494
@Test
9595
public void testCorrectScaleUpUsingDifferentSetBoundsMethod() {
96-
Win32DPIUtils.setMonitorSpecificScaling(true);
96+
AutoScaling.setMonitorSpecificScaling(true);
9797
Display display = Display.getDefault();
9898
Shell shell = new Shell(display);
9999
Button button = new Button(shell, SWT.PUSH);
@@ -114,7 +114,7 @@ public void testCorrectScaleUpUsingDifferentSetBoundsMethod() {
114114
@CsvSource({ "0.5, 100, true", "1.0, 200, true", "2.0, 200, true", "2.0, quarter, true", "0.5, 100, false",
115115
"1.0, 200, false", "2.0, 200, false", "2.0, quarter, false", })
116116
public void testAutoScaleImageData(float scaleFactor, String autoScale, boolean monitorSpecificScaling) {
117-
Win32DPIUtils.setMonitorSpecificScaling(monitorSpecificScaling);
117+
AutoScaling.setMonitorSpecificScaling(monitorSpecificScaling);
118118
DPIUtil.runWithAutoScaleValue(autoScale, () -> {
119119
Display display = new Display();
120120
try {

bundles/org.eclipse.swt/Eclipse SWT Tests/win32/org/eclipse/swt/widgets/DisplayWin32Test.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import static org.junit.jupiter.api.Assertions.*;
44

5+
import org.eclipse.swt.*;
56
import org.eclipse.swt.internal.*;
67
import org.eclipse.swt.internal.win32.*;
78
import org.junit.jupiter.api.*;
@@ -13,15 +14,15 @@ class DisplayWin32Test {
1314

1415
@Test
1516
public void monitorSpecificScaling_activate() {
16-
Win32DPIUtils.setMonitorSpecificScaling(true);
17+
AutoScaling.setMonitorSpecificScaling(true);
1718
Display display = Display.getDefault();
1819
assertTrue(display.isRescalingAtRuntime());
1920
assertEquals(OS.DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2, OS.GetThreadDpiAwarenessContext());
2021
}
2122

2223
@Test
2324
public void monitorSpecificScaling_deactivate() {
24-
Win32DPIUtils.setMonitorSpecificScaling(false);
25+
AutoScaling.setMonitorSpecificScaling(false);
2526
Display display = Display.getDefault();
2627
assertFalse(display.isRescalingAtRuntime());
2728
}
Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
package org.eclipse.swt;
2+
3+
import java.util.*;
4+
import java.util.function.*;
5+
6+
import org.eclipse.swt.internal.*;
7+
import org.eclipse.swt.internal.win32.*;
8+
import org.eclipse.swt.internal.win32.version.*;
9+
import org.eclipse.swt.widgets.*;
10+
11+
/**
12+
* Utility for checking and enabling monitor-specific auto scaling.
13+
* @since 3.132
14+
*/
15+
public final class AutoScaling {
16+
/**
17+
* System property to enable to scale the application on runtime
18+
* when a DPI change is detected.
19+
* <ul>
20+
* <li>"true": the application is scaled on DPI changes</li>
21+
* <li>"false": the application will remain in its initial scaling</li>
22+
* </ul>
23+
* <b>Important:</b> This flag is only parsed and used on Win32. Setting it to
24+
* true on GTK or cocoa will be ignored.
25+
*/
26+
private static final String SWT_AUTOSCALE_UPDATE_ON_RUNTIME = "swt.autoScale.updateOnRuntime";
27+
private static final String SWT_AUTOSCALE = "swt.autoScale";
28+
private static final String SWT_AUTOSCALE_DISABLE_COMPATIBILITY_CHECK = "swt.autoScale.force";
29+
private static String autoScaleValue;
30+
static {
31+
autoScaleValue = System.getProperty (SWT_AUTOSCALE);
32+
DPIUtil.setUseSmoothScalingByDefaultProvider(() -> isMonitorSpecificScalingActive());
33+
}
34+
private static final Set<String> ALLOWED_VALUES = Set.of("false", "quarter", "exact");
35+
private static final String WIN32_PLATFORM = "win32";
36+
37+
public static String getAutoScaleValue() {
38+
return autoScaleValue;
39+
}
40+
41+
/**
42+
* Returns {@code true} only if the current setup is compatible
43+
* with monitor-specific scaling. Returns {@code false} if:
44+
* <ul>
45+
* <li>Not running on Windows</li>
46+
* <li>The current auto-scale mode is incompatible</li>
47+
* </ul>
48+
*
49+
*/
50+
public static boolean isSetupCompatibleToMonitorSpecificScaling() {
51+
if("true".equalsIgnoreCase(System.getProperty(SWT_AUTOSCALE_DISABLE_COMPATIBILITY_CHECK))) {
52+
return true;
53+
}
54+
// Per-monitor DPI supported only on Windows
55+
if (!isWindows()) {
56+
return false;
57+
}
58+
59+
// Default means: treat as "quarter" (compatible)
60+
if (autoScaleValue == null) {
61+
return true;
62+
}
63+
64+
String value = autoScaleValue.toLowerCase(Locale.ROOT);
65+
66+
// Compatible only if one of the known values
67+
return ALLOWED_VALUES.contains(value);
68+
}
69+
70+
/**
71+
* Enables monitor-specific scaling *regardless of compatibility*.
72+
*/
73+
public static void enableMonitorSpecificScaling() {
74+
System.setProperty(SWT_AUTOSCALE_UPDATE_ON_RUNTIME, "true");
75+
}
76+
77+
public static void setAutoScaleForMonitorSpecificScaling() {
78+
boolean isDefaultAutoScale = autoScaleValue == null;
79+
if (isDefaultAutoScale) {
80+
autoScaleValue = "quarter";
81+
}
82+
}
83+
84+
public static boolean isMonitorSpecificScalingActive() {
85+
boolean updateOnRuntimeValue = Boolean.getBoolean (SWT_AUTOSCALE_UPDATE_ON_RUNTIME);
86+
return updateOnRuntimeValue;
87+
}
88+
89+
/**
90+
* Runs the given {@link Runnable} under a temporarily applied auto-scale
91+
* value, restoring the previous value afterwards. Intended as the public
92+
* replacement for the internal DPIUtil#runWithAutoScaleValue().
93+
*/
94+
public static void runWithAutoScaleValue(String autoScaleValue, Runnable code) {
95+
String initialAutoScaleValue = autoScaleValue;
96+
AutoScaling.autoScaleValue = autoScaleValue;
97+
DPIUtil.setDeviceZoom(DPIUtil.getZoomForAutoscaleProperty(DPIUtil.getNativeDeviceZoom()));
98+
try {
99+
code.run();
100+
} finally {
101+
AutoScaling.autoScaleValue = initialAutoScaleValue;
102+
DPIUtil.setDeviceZoom(DPIUtil.getZoomForAutoscaleProperty(DPIUtil.getNativeDeviceZoom()));
103+
}
104+
}
105+
106+
private static boolean isWindows() {
107+
return WIN32_PLATFORM.equals(SWT.getPlatform());
108+
}
109+
110+
public static void setMonitorSpecificScaling(boolean activate) {
111+
System.setProperty(SWT_AUTOSCALE_UPDATE_ON_RUNTIME, Boolean.toString(activate));
112+
}
113+
114+
public static boolean setDPIAwareness(int desiredDpiAwareness) {
115+
if (desiredDpiAwareness == OS.GetThreadDpiAwarenessContext()) {
116+
return true;
117+
}
118+
if (desiredDpiAwareness == OS.DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2) {
119+
// "Per Monitor V2" only available in more recent Windows version
120+
boolean perMonitorV2Available = OsVersion.IS_WIN10_1809;
121+
if (!perMonitorV2Available) {
122+
System.err.println("***WARNING: the OS version does not support DPI awareness mode PerMonitorV2.");
123+
return false;
124+
}
125+
}
126+
long setDpiAwarenessResult = OS.SetThreadDpiAwarenessContext(desiredDpiAwareness);
127+
if (setDpiAwarenessResult == 0L) {
128+
System.err.println("***WARNING: setting DPI awareness failed.");
129+
return false;
130+
}
131+
return true;
132+
}
133+
134+
public static <T> T runWithProperDPIAwareness(Display display, Supplier<T> operation) {
135+
// only with monitor-specific scaling enabled, the main thread's DPI awareness may be adapted
136+
if (!display.isRescalingAtRuntime()) {
137+
return operation.get();
138+
}
139+
long previousDPIAwareness = OS.GetThreadDpiAwarenessContext();
140+
try {
141+
if (!setDPIAwareness(OS.DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2)) {
142+
// awareness was not changed, so no need to reset it
143+
previousDPIAwareness = 0;
144+
}
145+
return operation.get();
146+
} finally {
147+
if (previousDPIAwareness > 0) {
148+
OS.SetThreadDpiAwarenessContext(previousDPIAwareness);
149+
}
150+
}
151+
}
152+
}

bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/DPIUtil.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -363,13 +363,13 @@ public static void setDeviceZoom (int nativeDeviceZoom) {
363363
}
364364

365365
@FunctionalInterface
366-
interface UseSmoothScalingProvider {
366+
public interface UseSmoothScalingProvider {
367367
boolean shouldUseSmoothScaling();
368368
}
369369

370370
private static UseSmoothScalingProvider useSmoothScalingByDefaultProvider = () -> false;
371371

372-
static void setUseSmoothScalingByDefaultProvider(UseSmoothScalingProvider provider) {
372+
public static void setUseSmoothScalingByDefaultProvider(UseSmoothScalingProvider provider) {
373373
useSmoothScalingByDefaultProvider = provider;
374374
}
375375

0 commit comments

Comments
 (0)