Skip to content

Commit 31f1b58

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 079d2a9 commit 31f1b58

File tree

8 files changed

+164
-115
lines changed

8 files changed

+164
-115
lines changed

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: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2025 Yatta 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 - initial API and implementation
13+
*******************************************************************************/
14+
package org.eclipse.swt;
15+
16+
import java.util.*;
17+
18+
import org.eclipse.swt.internal.*;
19+
20+
/**
21+
* Utility for checking and enabling monitor-specific auto scaling.
22+
* @since 3.132
23+
*/
24+
public final class AutoScaling {
25+
/**
26+
* System property to enable to scale the application on runtime
27+
* when a DPI change is detected.
28+
* <ul>
29+
* <li>"true": the application is scaled on DPI changes</li>
30+
* <li>"false": the application will remain in its initial scaling</li>
31+
* </ul>
32+
* <b>Important:</b> This flag is only parsed and used on Win32. Setting it to
33+
* true on GTK or cocoa will be ignored.
34+
*/
35+
private static final String SWT_AUTOSCALE_UPDATE_ON_RUNTIME = "swt.autoScale.updateOnRuntime";
36+
private static final String SWT_AUTOSCALE = "swt.autoScale";
37+
private static final String SWT_AUTOSCALE_DISABLE_COMPATIBILITY_CHECK = "swt.autoScale.force";
38+
private static String autoScaleValue;
39+
static {
40+
autoScaleValue = System.getProperty (SWT_AUTOSCALE);
41+
}
42+
private static final Set<String> ALLOWED_VALUES = Set.of("false", "quarter", "exact");
43+
private static final String WIN32_PLATFORM = "win32";
44+
45+
/**
46+
* Returns the current auto-scale value.
47+
*/
48+
public static String getAutoScaleValue() {
49+
return autoScaleValue;
50+
}
51+
52+
/**
53+
* Sets the current auto-scale value.
54+
*/
55+
public static void setAutoScaleValue(String autoScaleValueArg) {
56+
autoScaleValue = autoScaleValueArg;
57+
}
58+
59+
/**
60+
* Returns {@code true} only if the current setup is compatible
61+
* with monitor-specific scaling. Returns {@code false} if:
62+
* <ul>
63+
* <li>Not running on Windows</li>
64+
* <li>The current auto-scale mode is incompatible</li>
65+
* </ul>
66+
*
67+
* <p>Allowed values: {@code false}, {@code quarter}, {@code exact}.
68+
*
69+
*/
70+
public static boolean isSetupCompatibleToMonitorSpecificScaling() {
71+
if("true".equalsIgnoreCase(System.getProperty(SWT_AUTOSCALE_DISABLE_COMPATIBILITY_CHECK))) {
72+
return true;
73+
}
74+
// Per-monitor DPI supported only on Windows
75+
if (!isWindows()) {
76+
return false;
77+
}
78+
79+
// Default means: treat as "quarter" (compatible)
80+
if (autoScaleValue == null) {
81+
return true;
82+
}
83+
84+
String value = autoScaleValue.toLowerCase(Locale.ROOT);
85+
86+
// Compatible only if one of the known values
87+
return ALLOWED_VALUES.contains(value);
88+
}
89+
90+
/**
91+
* Enables monitor-specific scaling *regardless of compatibility*.
92+
*/
93+
public static void enableMonitorSpecificScaling() {
94+
System.setProperty(SWT_AUTOSCALE_UPDATE_ON_RUNTIME, "true");
95+
}
96+
97+
/**
98+
* For monitor-specific scaling, ensures that the auto-scale value is set to quarter (default)
99+
* if it was not explicitly set before.
100+
*/
101+
public static void setAutoScaleForMonitorSpecificScaling() {
102+
boolean isDefaultAutoScale = autoScaleValue == null;
103+
if (isDefaultAutoScale) {
104+
autoScaleValue = "quarter";
105+
}
106+
}
107+
108+
/**
109+
* Returns {@code true} if monitor-specific scaling is active
110+
*/
111+
public static boolean isMonitorSpecificScalingActive() {
112+
boolean updateOnRuntimeValue = Boolean.getBoolean (SWT_AUTOSCALE_UPDATE_ON_RUNTIME);
113+
return updateOnRuntimeValue;
114+
}
115+
116+
/**
117+
* Runs the given {@link Runnable} under a temporarily applied auto-scale
118+
* value, restoring the previous value afterwards. Intended as the public
119+
* replacement for the internal DPIUtil#runWithAutoScaleValue().
120+
*/
121+
public static void runWithAutoScaleValue(String autoScaleValue, Runnable code) {
122+
String initialAutoScaleValue = autoScaleValue;
123+
AutoScaling.autoScaleValue = autoScaleValue;
124+
DPIUtil.setDeviceZoom(DPIUtil.getZoomForAutoscaleProperty(DPIUtil.getNativeDeviceZoom()));
125+
try {
126+
code.run();
127+
} finally {
128+
AutoScaling.autoScaleValue = initialAutoScaleValue;
129+
DPIUtil.setDeviceZoom(DPIUtil.getZoomForAutoscaleProperty(DPIUtil.getNativeDeviceZoom()));
130+
}
131+
}
132+
133+
private static boolean isWindows() {
134+
return WIN32_PLATFORM.equals(SWT.getPlatform());
135+
}
136+
137+
/**
138+
* Activates or deactivates monitor-specific scaling.
139+
*/
140+
public static void setMonitorSpecificScaling(boolean activate) {
141+
System.setProperty(SWT_AUTOSCALE_UPDATE_ON_RUNTIME, Boolean.toString(activate));
142+
}
143+
}

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

Lines changed: 4 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -49,32 +49,6 @@ public static Optional<AutoScaleMethod> forString(String s) {
4949
private static final AutoScaleMethod AUTO_SCALE_METHOD_SETTING;
5050
private static AutoScaleMethod autoScaleMethod;
5151

52-
private static String autoScaleValue;
53-
54-
/**
55-
* System property that controls the autoScale functionality.
56-
* <ul>
57-
* <li><b>false</b>: deviceZoom is set to 100%</li>
58-
* <li><b>integer</b>: deviceZoom depends on the current display resolution,
59-
* but only uses integer multiples of 100%. The detected native zoom is
60-
* generally rounded down (e.g. at 150%, will use 100%), unless close to
61-
* the next integer multiple (currently at 175%, will use 200%).</li>
62-
* <li><b>integer200</b>: like <b>integer</b>, but the maximal zoom level is 200%.</li>
63-
* <li><b>half</b>: deviceZoom depends on the current display resolution,
64-
* but only uses integer multiples of 50%. The detected native zoom is
65-
* rounded to the closest permissible value, with tie-breaker towards even.</li>
66-
* <li><b>quarter</b>: deviceZoom depends on the current display resolution,
67-
* but only uses integer multiples of 25%. The detected native zoom is
68-
* rounded to the closest permissible value.</li>
69-
* <li><b>exact</b>: deviceZoom uses the native zoom (with 1% as minimal
70-
* step).</li>
71-
* <li><i>&lt;value&gt;</i>: deviceZoom uses the given integer value in
72-
* percent as zoom level.</li>
73-
* </ul>
74-
* The current default is "integer200".
75-
*/
76-
private static final String SWT_AUTOSCALE = "swt.autoScale";
77-
7852
/**
7953
* System property that controls the method for scaling images:
8054
* <ul>
@@ -88,21 +62,11 @@ public static Optional<AutoScaleMethod> forString(String s) {
8862
private static final String SWT_AUTOSCALE_METHOD = "swt.autoScale.method";
8963

9064
static {
91-
autoScaleValue = System.getProperty (SWT_AUTOSCALE);
92-
9365
String value = System.getProperty (SWT_AUTOSCALE_METHOD);
9466
AUTO_SCALE_METHOD_SETTING = AutoScaleMethod.forString(value).orElse(AutoScaleMethod.AUTO);
9567
autoScaleMethod = AUTO_SCALE_METHOD_SETTING != AutoScaleMethod.AUTO ? AUTO_SCALE_METHOD_SETTING : AutoScaleMethod.NEAREST;
9668
}
9769

98-
static String getAutoScaleValue() {
99-
return autoScaleValue;
100-
}
101-
102-
static void setAutoScaleValue(String autoScaleValueArg) {
103-
autoScaleValue = autoScaleValueArg;
104-
}
105-
10670
public static int pixelToPoint(int size, int zoom) {
10771
if (zoom == 100 || size == SWT.DEFAULT) return size;
10872
float scaleFactor = getScalingFactor (zoom);
@@ -374,7 +338,7 @@ static void setUseSmoothScalingByDefaultProvider(UseSmoothScalingProvider provid
374338
}
375339

376340
public static int getZoomForAutoscaleProperty (int nativeDeviceZoom) {
377-
return getZoomForAutoscaleProperty(nativeDeviceZoom, autoScaleValue);
341+
return getZoomForAutoscaleProperty(nativeDeviceZoom, AutoScaling.getAutoScaleValue());
378342
}
379343

380344
private static int getZoomForAutoscaleProperty (int nativeDeviceZoom, String autoScaleValue) {
@@ -407,13 +371,13 @@ private static int getZoomForAutoscaleProperty (int nativeDeviceZoom, String aut
407371
}
408372

409373
public static void runWithAutoScaleValue(String autoScaleValue, Runnable runnable) {
410-
String initialAutoScaleValue = DPIUtil.autoScaleValue;
411-
DPIUtil.autoScaleValue = autoScaleValue;
374+
String initialAutoScaleValue = AutoScaling.getAutoScaleValue();
375+
AutoScaling.setAutoScaleValue(autoScaleValue);
412376
DPIUtil.deviceZoom = getZoomForAutoscaleProperty(nativeDeviceZoom);
413377
try {
414378
runnable.run();
415379
} finally {
416-
DPIUtil.autoScaleValue = initialAutoScaleValue;
380+
AutoScaling.setAutoScaleValue(initialAutoScaleValue);
417381
DPIUtil.deviceZoom = getZoomForAutoscaleProperty(nativeDeviceZoom);
418382
}
419383
}

0 commit comments

Comments
 (0)