diff --git a/bundles/org.eclipse.swt/Eclipse SWT Tests/win32/org/eclipse/swt/widgets/ControlWin32Tests.java b/bundles/org.eclipse.swt/Eclipse SWT Tests/win32/org/eclipse/swt/widgets/ControlWin32Tests.java index 66f0b3c400..ecce8aff23 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT Tests/win32/org/eclipse/swt/widgets/ControlWin32Tests.java +++ b/bundles/org.eclipse.swt/Eclipse SWT Tests/win32/org/eclipse/swt/widgets/ControlWin32Tests.java @@ -111,7 +111,7 @@ public void testCorrectScaleUpUsingDifferentSetBoundsMethod() { } @ParameterizedTest - @CsvSource({ "0.5, 100, true", "1.0, 200, true", "2.0, 200, true", "2.0, quarter, true", "0.5, 100, false", + @CsvSource({ "2.0, quarter, true", "0.5, 100, false", "1.0, 200, false", "2.0, 200, false", "2.0, quarter, false", }) public void testAutoScaleImageData(float scaleFactor, String autoScale, boolean monitorSpecificScaling) { Win32DPIUtils.setMonitorSpecificScaling(monitorSpecificScaling); diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/DPIUtil.java b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/DPIUtil.java index fced84b43e..4bee8ad9f3 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/DPIUtil.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/DPIUtil.java @@ -50,6 +50,17 @@ public static Optional forString(String s) { private static AutoScaleMethod autoScaleMethod; private static String autoScaleValue; + /** + * System property to enable to scale the application on runtime + * when a DPI change is detected. + * + * Important: This flag is only parsed and used on Win32. Setting it to + * true on GTK or cocoa will be ignored. + */ + static final String SWT_AUTOSCALE_UPDATE_ON_RUNTIME = "swt.autoScale.updateOnRuntime"; /** * System property that controls the autoScale functionality. @@ -87,6 +98,14 @@ public static Optional forString(String s) { */ private static final String SWT_AUTOSCALE_METHOD = "swt.autoScale.method"; + /** + * System property that enforces to use autoScale value despite incompatibility + * For e.g. Monitor-specific scaling with int200 autoscale value + */ + private static final String SWT_AUTOSCALE_DISABLE_COMPATIBILITY_CHECK = "swt.autoScale.force"; + + private static final Set ALLOWED_AUTOSCALE_VALUES_FOR_UPDATE_ON_RUNTIME = Set.of("quarter", "exact"); + static { autoScaleValue = System.getProperty (SWT_AUTOSCALE); @@ -95,7 +114,7 @@ public static Optional forString(String s) { autoScaleMethod = AUTO_SCALE_METHOD_SETTING != AutoScaleMethod.AUTO ? AUTO_SCALE_METHOD_SETTING : AutoScaleMethod.NEAREST; } -static String getAutoScaleValue() { +public static String getAutoScaleValue() { return autoScaleValue; } @@ -103,6 +122,39 @@ static void setAutoScaleValue(String autoScaleValueArg) { autoScaleValue = autoScaleValueArg; } +/** + * Returns {@code true} only if the current setup is compatible + * with monitor-specific scaling. Returns {@code false} if: + *
    + *
  • Not running on Windows
  • + *
  • The current auto-scale mode is incompatible
  • + *
+ * + *

Allowed values: {@code quarter}, {@code exact}. + * + */ +public static boolean isSetupCompatibleToMonitorSpecificScaling() { + // Per-monitor DPI supported only on Windows + if (!"win32".equals(SWT.getPlatform())) { + return false; + } + + // Default means: treat as "quarter" (compatible) + if (autoScaleValue == null || "true".equalsIgnoreCase(System.getProperty(SWT_AUTOSCALE_DISABLE_COMPATIBILITY_CHECK))) { + return true; + } + + String value = autoScaleValue.toLowerCase(Locale.ROOT); + + // Compatible only if one of the known values + return ALLOWED_AUTOSCALE_VALUES_FOR_UPDATE_ON_RUNTIME.contains(value); +} + +public static boolean isMonitorSpecificScalingActive() { + boolean updateOnRuntimeValue = Boolean.getBoolean (DPIUtil.SWT_AUTOSCALE_UPDATE_ON_RUNTIME); + return updateOnRuntimeValue; +} + public static int pixelToPoint(int size, int zoom) { if (zoom == 100 || size == SWT.DEFAULT) return size; float scaleFactor = getScalingFactor (zoom); diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/internal/Win32DPIUtils.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/internal/Win32DPIUtils.java index 078e81ac02..2d565750bd 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/internal/Win32DPIUtils.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/internal/Win32DPIUtils.java @@ -33,18 +33,6 @@ * @noreference This class is not intended to be referenced by clients */ public class Win32DPIUtils { - /** - * System property to enable to scale the application on runtime - * when a DPI change is detected. - *

    - *
  • "true": the application is scaled on DPI changes
  • - *
  • "false": the application will remain in its initial scaling
  • - *
- * Important: This flag is only parsed and used on Win32. Setting it to - * true on GTK or cocoa will be ignored. - */ - private static final String SWT_AUTOSCALE_UPDATE_ON_RUNTIME = "swt.autoScale.updateOnRuntime"; - static { DPIUtil.setUseSmoothScalingByDefaultProvider(() -> isMonitorSpecificScalingActive()); } @@ -278,53 +266,22 @@ public static Rectangle pointToPixel(Drawable drawable, Rectangle rect, int zoom } public static void setMonitorSpecificScaling(boolean activate) { - System.setProperty(SWT_AUTOSCALE_UPDATE_ON_RUNTIME, Boolean.toString(activate)); + System.setProperty(DPIUtil.SWT_AUTOSCALE_UPDATE_ON_RUNTIME, Boolean.toString(activate)); } public static void setAutoScaleForMonitorSpecificScaling() { boolean isDefaultAutoScale = DPIUtil.getAutoScaleValue() == null; if (isDefaultAutoScale) { DPIUtil.setAutoScaleValue("quarter"); - } else if (!isSupportedAutoScaleForMonitorSpecificScaling()) { + } else if (!DPIUtil.isSetupCompatibleToMonitorSpecificScaling()) { throw new SWTError(SWT.ERROR_NOT_IMPLEMENTED, "monitor-specific scaling is only implemented for auto-scale values \"quarter\", \"exact\", \"false\" or a concrete zoom value, but \"" + DPIUtil.getAutoScaleValue() + "\" has been specified"); } } - /** - * Monitor-specific scaling on Windows only supports auto-scale modes in which - * all elements (font, images, control bounds etc.) are scaled equally or almost - * equally. The previously default mode "integer"/"integer200", which rounded - * the scale factor for everything but fonts to multiples of 100, is complex and - * difficult to realize with monitor-specific rescaling of UI elements. Since a - * uniform scale factor for everything should perspectively be used anyway, - * there will be support for complex auto-scale modes for monitor-specific - * scaling. - * - * The supported modes are "quarter" and "exact" or explicit zoom values given - * by the value itself or "false". Every other value will be treated as - * "integer"/"integer200" and is thus not supported. - */ - private static boolean isSupportedAutoScaleForMonitorSpecificScaling() { - if (DPIUtil.getAutoScaleValue() == null) { - return false; - } - switch (DPIUtil.getAutoScaleValue().toLowerCase()) { - case "false", "quarter", "exact": return true; - } - try { - Integer.parseInt(DPIUtil.getAutoScaleValue()); - return true; - } catch (NumberFormatException e) { - // unsupported value, use default - } - return false; - } - public static boolean isMonitorSpecificScalingActive() { - boolean updateOnRuntimeValue = Boolean.getBoolean (SWT_AUTOSCALE_UPDATE_ON_RUNTIME); - return updateOnRuntimeValue; + return DPIUtil.isMonitorSpecificScalingActive(); } public static int getPrimaryMonitorZoomAtStartup() {