Skip to content

Commit 4a818d1

Browse files
committed
Assign Windows runtime rescaling to Display instead of DPIUtil
Currently, the runtime rescaling of shells/widgets on Windows is tied to a property in the DPIUtil class. Since that class is internal, the property can only be set via a VM argument at startup but cannot be changed or at least retrieved during runtime from outside the SWT bundle. This change reduces the DPIUtil property to a global setting that may be used to set the behavior for a whole application (in particular an SWT application) but move the actual state handling for runtime rescaling behavior to the Display class. This allow to retrieve and change the value directly on the Display, on which also the DPI awareness for the UI thread is initialized. As a side effect, it improves testability as a properly configured display can be used instead of changing the global state of DPIUtil.
1 parent 7a8fda3 commit 4a818d1

File tree

10 files changed

+132
-71
lines changed

10 files changed

+132
-71
lines changed

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

Lines changed: 0 additions & 24 deletions
This file was deleted.

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

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
public abstract class Win32AutoscaleTestBase {
2121
protected Display display;
2222
protected Shell shell;
23-
private boolean autoScaleOnRuntime;
2423

2524
@BeforeAll
2625
public static void assumeIsFittingPlatform() {
@@ -29,9 +28,8 @@ public static void assumeIsFittingPlatform() {
2928

3029
@BeforeEach
3130
public void setUpTest() {
32-
autoScaleOnRuntime = DPITestUtil.isAutoScaleOnRuntimeActive();
3331
display = Display.getDefault();
34-
autoScaleOnRuntime(true);
32+
display.setRescalingAtRuntime(true);
3533
shell = new Shell(display);
3634
}
3735

@@ -40,13 +38,7 @@ public void tearDownTest() {
4038
if (shell != null) {
4139
shell.dispose();
4240
}
43-
autoScaleOnRuntime(autoScaleOnRuntime);
44-
}
45-
46-
protected void autoScaleOnRuntime (boolean autoScaleOnRuntime) {
47-
DPITestUtil.setAutoScaleOnRunTime(autoScaleOnRuntime);
48-
// dispose a existing font registry for the default display
49-
SWTFontProvider.disposeFontRegistry(display);
41+
display.dispose();
5042
}
5143

5244
protected void changeDPIZoom (int nativeZoom) {

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ class ControlWin32Tests extends Win32AutoscaleTestBase {
3030

3131
@Test
3232
public void testScaleFontCorrectlyInAutoScaleSzenario() {
33-
assertTrue("Autoscale property is not set to true", DPITestUtil.isAutoScaleOnRuntimeActive());
33+
assertTrue("Autoscale property is not set to true", display.isRescalingAtRuntime());
3434

3535
int scalingFactor = 2;
3636
Control control = new Composite(shell, SWT.NONE);
@@ -54,8 +54,8 @@ public void testScaleFontCorrectlyInAutoScaleSzenario() {
5454

5555
@Test
5656
public void testDoNotScaleFontCorrectlyInNoAutoScaleSzenario() {
57-
autoScaleOnRuntime(false);
58-
assertFalse("Autoscale property is not set to false", DPITestUtil.isAutoScaleOnRuntimeActive());
57+
display.setRescalingAtRuntime(false);
58+
assertFalse("Autoscale property is not set to false", display.isRescalingAtRuntime());
5959

6060
int scalingFactor = 2;
6161
Control control = new Composite(shell, SWT.NONE);

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

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6832,4 +6832,33 @@ static long windowProc(long id, long sel, long arg0, long arg1, long arg2, long
68326832
static boolean isActivateShellOnForceFocus() {
68336833
return "true".equals(System.getProperty("org.eclipse.swt.internal.activateShellOnForceFocus", "true")); //$NON-NLS-1$
68346834
}
6835+
6836+
/**
6837+
* {@return whether rescaling of shells at runtime when the DPI scaling of a
6838+
* shell's monitor changes is activated for this device}
6839+
* <p>
6840+
* <b>Note:</b> This functionality is only available on Windows. Calling this
6841+
* method on other operating system will always return false.
6842+
*
6843+
* @since 3.127
6844+
*/
6845+
public boolean isRescalingAtRuntime() {
6846+
return false;
6847+
}
6848+
6849+
/**
6850+
* Activates or deactivates rescaling of shells at runtime whenever the DPI
6851+
* scaling of the shell's monitor changes. This is only safe to call as long as
6852+
* no shell has been created for this display. When changing the value after a
6853+
* shell has been created for this display, the effect is undefined.
6854+
* <p>
6855+
* <b>Note:</b> This functionality is only available on Windows. Calling this
6856+
* method on other operating system will have no effect.
6857+
*
6858+
* @param activate whether rescaling shall be activated or deactivated
6859+
* @since 3.127
6860+
*/
6861+
public void setRescalingAtRuntime(boolean activate) {
6862+
// not implemented for Cocoa
6863+
}
68356864
}

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

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -110,10 +110,8 @@ private static enum AutoScaleMethod { AUTO, NEAREST, SMOOTH }
110110
}
111111
}
112112

113-
if ("win32".equals(SWT.getPlatform())) {
114-
String updateOnRuntimeValue = System.getProperty (SWT_AUTOSCALE_UPDATE_ON_RUNTIME);
115-
autoScaleOnRuntime = Boolean.parseBoolean(updateOnRuntimeValue);
116-
}
113+
String updateOnRuntimeValue = System.getProperty (SWT_AUTOSCALE_UPDATE_ON_RUNTIME);
114+
autoScaleOnRuntime = Boolean.parseBoolean(updateOnRuntimeValue);
117115
}
118116

119117
/**
@@ -669,10 +667,6 @@ public static boolean isAutoScaleOnRuntimeActive() {
669667
return autoScaleOnRuntime;
670668
}
671669

672-
static boolean setAutoScaleOnRuntimeActive(boolean value) {
673-
return autoScaleOnRuntime = value;
674-
}
675-
676670
/**
677671
* AutoScale ImageDataProvider.
678672
*/

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

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6266,4 +6266,34 @@ static int _getDeviceZoom (long monitor_num) {
62666266
static boolean isActivateShellOnForceFocus() {
62676267
return "true".equals(System.getProperty("org.eclipse.swt.internal.activateShellOnForceFocus", "true")); //$NON-NLS-1$
62686268
}
6269+
6270+
/**
6271+
* {@return whether rescaling of shells at runtime when the DPI scaling of a
6272+
* shell's monitor changes is activated for this device}
6273+
* <p>
6274+
* <b>Note:</b> This functionality is only available on Windows. Calling this
6275+
* method on other operating system will always return false.
6276+
*
6277+
* @since 3.127
6278+
*/
6279+
public boolean isRescalingAtRuntime() {
6280+
return false;
6281+
}
6282+
6283+
/**
6284+
* Activates or deactivates rescaling of shells at runtime whenever the DPI
6285+
* scaling of the shell's monitor changes. This is only safe to call as long as
6286+
* no shell has been created for this display. When changing the value after a
6287+
* shell has been created for this display, the effect is undefined.
6288+
* <p>
6289+
* <b>Note:</b> This functionality is only available on Windows. Calling this
6290+
* method on other operating system will have no effect.
6291+
*
6292+
* @param activate whether rescaling shall be activated or deactivated
6293+
* @since 3.127
6294+
*/
6295+
public void setRescalingAtRuntime(boolean activate) {
6296+
// not implemented for GTK
6297+
}
6298+
62696299
}

bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/internal/SWTFontProvider.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import java.util.*;
1717

1818
import org.eclipse.swt.graphics.*;
19+
import org.eclipse.swt.widgets.*;
1920

2021
/**
2122
* This internal class is used to provide and cache fonts scaled for different zoom levels in the win32
@@ -47,7 +48,7 @@ public static void disposeFontRegistry(Device device) {
4748
}
4849

4950
private static SWTFontRegistry newFontRegistry(Device device) {
50-
if (DPIUtil.isAutoScaleOnRuntimeActive()) {
51+
if (device instanceof Display display && display.isRescalingAtRuntime()) {
5152
return new ScalingSWTFontRegistry(device);
5253
}
5354
return new DefaultSWTFontRegistry(device);

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4910,13 +4910,13 @@ LRESULT WM_DPICHANGED (long wParam, long lParam) {
49104910
event.detail = newNativeZoom;
49114911
event.doit = true;
49124912

4913-
if (DPIUtil.isAutoScaleOnRuntimeActive()) {
4913+
if (getDisplay().isRescalingAtRuntime()) {
49144914
DPIUtil.setDeviceZoom (newNativeZoom);
49154915
}
49164916

49174917
notifyListeners(SWT.ZoomChanged, event);
49184918

4919-
if (DPIUtil.isAutoScaleOnRuntimeActive()) {
4919+
if (getDisplay().isRescalingAtRuntime()) {
49204920
RECT rect = new RECT ();
49214921
COM.MoveMemory(rect, lParam, RECT.sizeof);
49224922
this.setBoundsInPixels(rect.left, rect.top, rect.right - rect.left, rect.bottom-rect.top);

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

Lines changed: 61 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ public class Display extends Device implements Executor {
138138
EventTable eventTable, filterTable;
139139
boolean useOwnDC;
140140
boolean externalEventLoop; // events are dispatched outside SWT, e.g. TrackPopupMenu or DoDragDrop
141+
private boolean rescalingAtRuntime;
141142

142143
/* Widget Table */
143144
private Map<Long, Control> controlByHandle;
@@ -582,28 +583,8 @@ public Display () {
582583
*/
583584
public Display (DeviceData data) {
584585
super (data);
585-
initializeProperDPIAwareness();
586-
}
587-
588-
private void initializeProperDPIAwareness() {
589-
if (!DPIUtil.isAutoScaleOnRuntimeActive()) {
590-
return;
591-
}
592-
// Auto scaling on runtime requires DPI awareness mode "Per Monitor V2"
593-
boolean perMonitorV2Available = OS.WIN32_BUILD > OS.WIN32_BUILD_WIN10_1809;
594-
if (!perMonitorV2Available) {
595-
System.err.println(
596-
"***WARNING: rescaling at runtime is activated but the OS version does not support required DPI awareness mode PerMonitorV2.");
597-
return;
598-
}
599-
600-
boolean alreadyUsesPerMonitorV2 = OS.GetThreadDpiAwarenessContext() == OS.DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2;
601-
if (alreadyUsesPerMonitorV2) {
602-
return;
603-
}
604-
long setDpiAwarenessResult = OS.SetThreadDpiAwarenessContext(OS.DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
605-
if (setDpiAwarenessResult == 0L) {
606-
System.err.println("***WARNING: setting DPI awareness to PerMonitorV2 failed.");
586+
if (DPIUtil.isAutoScaleOnRuntimeActive()) {
587+
setRescalingAtRuntime(true);
607588
}
608589
}
609590

@@ -5267,4 +5248,62 @@ static String withCrLf (String string) {
52675248
static boolean isActivateShellOnForceFocus() {
52685249
return "true".equals(System.getProperty("org.eclipse.swt.internal.activateShellOnForceFocus", "true")); //$NON-NLS-1$
52695250
}
5251+
5252+
/**
5253+
* {@return whether rescaling of shells at runtime when the DPI scaling of a
5254+
* shell's monitor changes is activated for this device}
5255+
* <p>
5256+
* <b>Note:</b> This functionality is only available on Windows. Calling this
5257+
* method on other operating system will always return false.
5258+
*
5259+
* @since 3.127
5260+
*/
5261+
public boolean isRescalingAtRuntime() {
5262+
return rescalingAtRuntime;
5263+
}
5264+
5265+
/**
5266+
* Activates or deactivates rescaling of shells at runtime whenever the DPI
5267+
* scaling of the shell's monitor changes. This is only safe to call as long as
5268+
* no shell has been created for this display. When changing the value after a
5269+
* shell has been created for this display, the effect is undefined.
5270+
* <p>
5271+
* <b>Note:</b> This functionality is only available on Windows. Calling this
5272+
* method on other operating system will have no effect.
5273+
*
5274+
* @param activate whether rescaling shall be activated or deactivated
5275+
* @since 3.127
5276+
*/
5277+
public void setRescalingAtRuntime(boolean activate) {
5278+
rescalingAtRuntime = activate;
5279+
// dispose a existing font registry for the default display
5280+
SWTFontProvider.disposeFontRegistry(this);
5281+
setProperDPIAwareness();
5282+
}
5283+
5284+
private void setProperDPIAwareness() {
5285+
long desiredDpiAwareness = OS.DPI_AWARENESS_CONTEXT_SYSTEM_AWARE;
5286+
if (OS.WIN32_BUILD < OS.WIN32_BUILD_WIN10_1607) {
5287+
System.err.println("***WARNING: the OS version does not support setting DPI awareness.");
5288+
return;
5289+
}
5290+
if (rescalingAtRuntime) {
5291+
desiredDpiAwareness = OS.DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2;
5292+
// Auto scaling on runtime requires DPI awareness mode "Per Monitor V2"
5293+
boolean perMonitorV2Available = OS.WIN32_BUILD >= OS.WIN32_BUILD_WIN10_1809;
5294+
if (!perMonitorV2Available) {
5295+
System.err.println(
5296+
"***WARNING: rescaling at runtime is activated but the OS version does not support required DPI awareness mode PerMonitorV2.");
5297+
return;
5298+
}
5299+
}
5300+
if (desiredDpiAwareness == OS.GetThreadDpiAwarenessContext()) {
5301+
return;
5302+
}
5303+
long setDpiAwarenessResult = OS.SetThreadDpiAwarenessContext(desiredDpiAwareness);
5304+
if (setDpiAwarenessResult == 0L) {
5305+
System.err.println("***WARNING: setting DPI awareness failed.");
5306+
}
5307+
}
5308+
52705309
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -313,7 +313,7 @@ public Shell (Display display, int style) {
313313
createWidget ();
314314

315315

316-
if (DPIUtil.isAutoScaleOnRuntimeActive()) {
316+
if (getDisplay().isRescalingAtRuntime()) {
317317
addListener(SWT.ZoomChanged, this::handleZoomEvent);
318318
}
319319
}

0 commit comments

Comments
 (0)