From dec04c1d917331622fab52879506dab160668f2e Mon Sep 17 00:00:00 2001 From: Heiko Klare Date: Wed, 24 Jul 2024 15:08:59 +0200 Subject: [PATCH] Only consider rescaling at runtime enabled when DPI awareness mode fits Activating rescaling at runtime requires a proper DPI awareness mode to be set. Currently, if setting the DPI awareness mode fails, rescaling may still be activated if the user requested to. With this change, setting the rescaling mode of a Display ensures that the correct DPI awareness for the UI thread is set and, in case an error occurs, the rescaling mode is not changed. It also adapts some faulty constants and provides according test cases for setting the rescaling behavior. --- .../org/eclipse/swt/internal/win32/OS.java | 4 +- .../eclipse/swt/widgets/DisplayWin32Test.java | 55 +++++++++++++++++++ .../org/eclipse/swt/widgets/Display.java | 4 +- .../gtk/org/eclipse/swt/widgets/Display.java | 4 +- .../org/eclipse/swt/widgets/Display.java | 38 +++++++------ 5 files changed, 84 insertions(+), 21 deletions(-) create mode 100644 bundles/org.eclipse.swt/Eclipse SWT Tests/win32/org/eclipse/swt/widgets/DisplayWin32Test.java diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/win32/org/eclipse/swt/internal/win32/OS.java b/bundles/org.eclipse.swt/Eclipse SWT PI/win32/org/eclipse/swt/internal/win32/OS.java index 81648e352f1..c7b704ddcab 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT PI/win32/org/eclipse/swt/internal/win32/OS.java +++ b/bundles/org.eclipse.swt/Eclipse SWT PI/win32/org/eclipse/swt/internal/win32/OS.java @@ -369,8 +369,8 @@ public class OS extends C { public static final short DMDUP_SIMPLEX = 1; public static final short DMDUP_VERTICAL = 2; public static final short DMDUP_HORIZONTAL = 3; - public static final int DPI_AWARENESS_CONTEXT_UNAWARE = 16; - public static final int DPI_AWARENESS_CONTEXT_SYSTEM_AWARE = 17; + public static final int DPI_AWARENESS_CONTEXT_UNAWARE = 24592; + public static final int DPI_AWARENESS_CONTEXT_SYSTEM_AWARE = 24593; public static final int DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE = 18; public static final int DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 = 34; public static final int DSTINVERT = 0x550009; diff --git a/bundles/org.eclipse.swt/Eclipse SWT Tests/win32/org/eclipse/swt/widgets/DisplayWin32Test.java b/bundles/org.eclipse.swt/Eclipse SWT Tests/win32/org/eclipse/swt/widgets/DisplayWin32Test.java new file mode 100644 index 00000000000..dddd407cf0e --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT Tests/win32/org/eclipse/swt/widgets/DisplayWin32Test.java @@ -0,0 +1,55 @@ +package org.eclipse.swt.widgets; + +import static org.junit.jupiter.api.Assertions.*; + +import org.eclipse.swt.internal.*; +import org.eclipse.swt.internal.win32.*; +import org.junit.jupiter.api.*; + +public class DisplayWin32Test { + + private Display display; + + @BeforeAll + public static void assumeIsFittingPlatform() { + PlatformSpecificExecution.assumeIsFittingPlatform(); + } + + @BeforeEach + public void createDisplay() { + display = new Display(); + } + + @AfterEach + public void destroyDisplay() { + display.dispose(); + } + + @Test + public void setRescaleAtRuntime_activate() { + display.setRescalingAtRuntime(true); + assertTrue(display.isRescalingAtRuntime()); + assertEquals(OS.DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2, OS.GetThreadDpiAwarenessContext()); + } + + @Test + public void setRescaleAtRuntime_deactivate() { + display.setRescalingAtRuntime(false); + assertFalse(display.isRescalingAtRuntime()); + assertEquals(OS.DPI_AWARENESS_CONTEXT_SYSTEM_AWARE, OS.GetThreadDpiAwarenessContext()); + } + + @Test + public void setRescaleAtRuntime_toggling() { + display.setRescalingAtRuntime(false); + assertFalse(display.isRescalingAtRuntime()); + assertEquals(OS.DPI_AWARENESS_CONTEXT_SYSTEM_AWARE, OS.GetThreadDpiAwarenessContext()); + display.setRescalingAtRuntime(true); + assertTrue(display.isRescalingAtRuntime()); + assertEquals(OS.DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2, OS.GetThreadDpiAwarenessContext()); + display.setRescalingAtRuntime(false); + assertFalse(display.isRescalingAtRuntime()); + assertEquals(OS.DPI_AWARENESS_CONTEXT_SYSTEM_AWARE, OS.GetThreadDpiAwarenessContext()); + } + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Display.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Display.java index ecf7d471a73..98ee06cad3c 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Display.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Display.java @@ -6856,9 +6856,11 @@ public boolean isRescalingAtRuntime() { * method on other operating system will have no effect. * * @param activate whether rescaling shall be activated or deactivated + * @return whether activating or deactivating the rescaling was successful * @since 3.127 */ -public void setRescalingAtRuntime(boolean activate) { +public boolean setRescalingAtRuntime(boolean activate) { // not implemented for Cocoa + return false; } } diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Display.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Display.java index 0e1ed40617a..54323b0ac50 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Display.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Display.java @@ -6290,10 +6290,12 @@ public boolean isRescalingAtRuntime() { * method on other operating system will have no effect. * * @param activate whether rescaling shall be activated or deactivated + * @return whether activating or deactivating the rescaling was successful * @since 3.127 */ -public void setRescalingAtRuntime(boolean activate) { +public boolean setRescalingAtRuntime(boolean activate) { // not implemented for GTK + return false; } } diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Display.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Display.java index 13c0e43ffae..e919a2c0995 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Display.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Display.java @@ -5272,38 +5272,42 @@ public boolean isRescalingAtRuntime() { * method on other operating system will have no effect. * * @param activate whether rescaling shall be activated or deactivated + * @return whether activating or deactivating the rescaling was successful * @since 3.127 */ -public void setRescalingAtRuntime(boolean activate) { - rescalingAtRuntime = activate; - // dispose a existing font registry for the default display - SWTFontProvider.disposeFontRegistry(this); - setProperDPIAwareness(); +public boolean setRescalingAtRuntime(boolean activate) { + int desiredApiAwareness = activate ? OS.DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 : OS.DPI_AWARENESS_CONTEXT_SYSTEM_AWARE; + if (setDPIAwareness(desiredApiAwareness)) { + rescalingAtRuntime = activate; + // dispose a existing font registry for the default display + SWTFontProvider.disposeFontRegistry(this); + return true; + } + return false; } -private void setProperDPIAwareness() { - long desiredDpiAwareness = OS.DPI_AWARENESS_CONTEXT_SYSTEM_AWARE; +private boolean setDPIAwareness(int desiredDpiAwareness) { if (OS.WIN32_BUILD < OS.WIN32_BUILD_WIN10_1607) { System.err.println("***WARNING: the OS version does not support setting DPI awareness."); - return; + return false; } - if (rescalingAtRuntime) { - desiredDpiAwareness = OS.DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2; - // Auto scaling on runtime requires DPI awareness mode "Per Monitor V2" + if (desiredDpiAwareness == OS.GetThreadDpiAwarenessContext()) { + return true; + } + if (desiredDpiAwareness == OS.DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2) { + // "Per Monitor V2" only available in more recent Windows version boolean perMonitorV2Available = OS.WIN32_BUILD >= OS.WIN32_BUILD_WIN10_1809; if (!perMonitorV2Available) { - System.err.println( - "***WARNING: rescaling at runtime is activated but the OS version does not support required DPI awareness mode PerMonitorV2."); - return; + System.err.println("***WARNING: the OS version does not support DPI awareness mode PerMonitorV2."); + return false; } } - if (desiredDpiAwareness == OS.GetThreadDpiAwarenessContext()) { - return; - } long setDpiAwarenessResult = OS.SetThreadDpiAwarenessContext(desiredDpiAwareness); if (setDpiAwarenessResult == 0L) { System.err.println("***WARNING: setting DPI awareness failed."); + return false; } + return true; } }