diff options
author | Sven Gothel <[email protected]> | 2023-01-31 22:57:23 +0100 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2023-01-31 22:57:23 +0100 |
commit | 7982cc52344c025c40da45fd4b946056a63bc855 (patch) | |
tree | 821c49296827111efc7b4b207ae4cc2726320559 | |
parent | ad38d1559854985b1131e5b6c7274a392b5bc265 (diff) |
NEWT Soft-PixelScale (p7): get{Global->}PixelScaleEnv(..): Support per monitor values w/ QT_SCREEN_SCALE_FACTORS syntax, use for X11v2.4.0
Per-monitor values are parsed if value is not a float and stored
in a given Map<String,float[2]>, parallel to a detected global_pixel_scale_xy.
The per-monitor value syntax matches QT_SCREEN_SCALE_FACTORS,
i.e. the regular expression '(<string>=<float>;)+',
e.g. QT_SCREEN_SCALE_FACTORS='DP-1=1.25;DP-2=1.25;HDMI-1=1.25;'
The per-monitor value is preferred and on X11 stored within the MonitorDevice,
matching the MonitorDevice's name.
The following env-var names are searched on X11:
"QT_SCREEN_SCALE_FACTORS", "QT_SCALE_FACTOR", "GDK_SCALE", "SOFT_SCALE"
4 files changed, 113 insertions, 28 deletions
diff --git a/src/nativewindow/classes/jogamp/nativewindow/SurfaceScaleUtils.java b/src/nativewindow/classes/jogamp/nativewindow/SurfaceScaleUtils.java index c732151e5..8f45001f9 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/SurfaceScaleUtils.java +++ b/src/nativewindow/classes/jogamp/nativewindow/SurfaceScaleUtils.java @@ -228,42 +228,106 @@ public class SurfaceScaleUtils { } /** + * Returns a proper string representation of the monitor-name to float[2] pixel-scale map. + */ + public static String toString(final Map<String,float[/*2*/]> monitorNameToScale) { + final StringBuilder sb = new StringBuilder(); + sb.append("{ "); + for(final String name: monitorNameToScale.keySet()) { + sb.append("'").append(name).append("'").append(" = ( "); + final float[] value = monitorNameToScale.get(name); + if( null != value && 2 == value.length ) { + sb.append(value[0]).append(" / ").append(value[1]); + } + sb.append(" ), "); + } + sb.append(" }"); + return sb.toString(); + } + + /** * Get global pixel-scale values from environment variables, e.g.: + * - QT_SCREEN_SCALE_FACTORS * - QT_SCALE_FACTOR * - GDK_SCALE * See https://wiki.archlinux.org/title/HiDPI * @param env_var_names array of potential environment variable names, treated as float. - * @param pixel_scale_xy store for resulting scale factors - * @return index of first found variable name within env_var_names, otherwise -1 + * @param global_pixel_scale_xy store for resulting scale factors + * @param monitorNameToScale storage mapping monitor names to their pixel_scale_xy, if variable value is of regular expression '(<string>=<float>;)+', + * i.e. QT_SCREEN_SCALE_FACTORS='DP-1=1.25;DP-2=1.25;HDMI-1=1.25;' + * @return index of first found global variable name within env_var_names, otherwise -1 */ - public static int getGlobalPixelScaleEnv(final String[] env_var_names, final float[] pixel_scale_xy) { + public static int getPixelScaleEnv(final String[] env_var_names, final float[] global_pixel_scale_xy, final Map<String,float[/*2*/]> monitorNameToScale) { final Map<String, String> env = SecurityUtil.doPrivileged(new PrivilegedAction<Map<String, String>>() { @Override public Map<String, String> run() { return System.getenv(); } }); - float value = -1.0f; + float global_value = -1.0f; + int global_idx = -1; + int mapping_idx = -1; boolean done = false; - int var_idx = 0; - while( var_idx < env_var_names.length && !done ) { + for(int var_idx = 0; var_idx < env_var_names.length && !done; ++var_idx ) { final String env_var_name = env_var_names[var_idx]; final String s_value = env.get(env_var_name); - if( null != s_value ) { - try { - value = Float.valueOf(s_value); - done = true; - } catch(final NumberFormatException nfe) { - ++var_idx; + if( null == s_value || s_value.isEmpty()) { + continue; // next + } + try { + final float v = Float.valueOf(s_value); + if( 0 > global_idx ) { // no overwrite + global_value = v; + global_idx = var_idx; + } + } catch(final NumberFormatException nfe) { + if( 0 <= mapping_idx ) { + continue; + } + // Attempt to parse regular expression '(<string>=<float>;)+', + // i.e. QT_SCREEN_SCALE_FACTORS='DP-1=1.25;DP-2=1.25;HDMI-1=1.25;' + final String[] pairs = s_value.split(";"); + if( null != pairs ) { + for(final String pair : pairs) { + if( null == pair || pair.isEmpty() ) { + continue; // empty is OK, next + } + final String[] elems = pair.split("="); + if( null == elems || 2 != elems.length ) { + // syntax error, bail out + monitorNameToScale.clear(); + break; + } + if( null == elems[0] || elems[0].isEmpty() ) { + // syntax error (empty name), bail out + monitorNameToScale.clear(); + break; + } + if( null == elems[1] || elems[1].isEmpty() ) { + // syntax error (empty value), bail out + monitorNameToScale.clear(); + break; + } + try { + final float pair_value = Float.valueOf(elems[1]); + monitorNameToScale.put(elems[0], new float[] { pair_value, pair_value} ); + mapping_idx = var_idx; + } catch(final NumberFormatException nfe2) { + // syntax error, bail out + monitorNameToScale.clear(); + break; + } + } } - } else { - ++var_idx; } + done = 0 <= mapping_idx && 0 <= global_idx; } - if( done ) { - pixel_scale_xy[0] = value; - pixel_scale_xy[1] = value; - return var_idx; + if( 0 <= global_idx ) { + global_pixel_scale_xy[0] = global_value; + global_pixel_scale_xy[1] = global_value; + return global_idx; + } else if( 0 <= mapping_idx ) { + return mapping_idx; } else { return -1; } diff --git a/src/newt/classes/jogamp/newt/driver/x11/ScreenDriver.java b/src/newt/classes/jogamp/newt/driver/x11/ScreenDriver.java index 1ffa26407..83929afe3 100644 --- a/src/newt/classes/jogamp/newt/driver/x11/ScreenDriver.java +++ b/src/newt/classes/jogamp/newt/driver/x11/ScreenDriver.java @@ -34,7 +34,9 @@ package jogamp.newt.driver.x11; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; import com.jogamp.nativewindow.AbstractGraphicsDevice; import com.jogamp.nativewindow.ScalableSurface; @@ -60,24 +62,33 @@ import com.jogamp.newt.MonitorMode; public class ScreenDriver extends ScreenImpl { protected static final boolean DEBUG_TEST_RANDR13_DISABLED; protected static final float[] global_pixel_scale = new float[] { ScalableSurface.AUTOMAX_PIXELSCALE, ScalableSurface.AUTOMAX_PIXELSCALE }; + protected static final Map<String,float[/*2*/]> monitor_pixel_scale_map = new HashMap<String, float[]>(); protected static final boolean global_pixel_scale_set; + protected static final boolean monitor_pixel_scale_map_set; static { Debug.initSingleton(); DEBUG_TEST_RANDR13_DISABLED = PropertyAccess.isPropertyDefined("newt.test.Screen.disableRandR13", true); - final String[] env_var_names = new String[] { "GDK_SCALE", "QT_SCALE_FACTOR", "SOFT_SCALE" }; + final String[] env_var_names = new String[] { "QT_SCREEN_SCALE_FACTORS", "QT_SCALE_FACTOR", "GDK_SCALE", "SOFT_SCALE" }; int var_name_idx = -1; try { - var_name_idx = SurfaceScaleUtils.getGlobalPixelScaleEnv(env_var_names, global_pixel_scale); + var_name_idx = SurfaceScaleUtils.getPixelScaleEnv(env_var_names, global_pixel_scale, monitor_pixel_scale_map); } catch (final Throwable t) { t.printStackTrace(); } if( 0 <= var_name_idx && var_name_idx < env_var_names.length ) { - global_pixel_scale_set = true; + global_pixel_scale_set = global_pixel_scale[0] != ScalableSurface.AUTOMAX_PIXELSCALE && global_pixel_scale[1] != ScalableSurface.AUTOMAX_PIXELSCALE; + monitor_pixel_scale_map_set = !monitor_pixel_scale_map.isEmpty(); if( DEBUG ) { - System.err.println("X11Screen: Global PixelScale Set: "+env_var_names[var_name_idx]+": "+global_pixel_scale[0]+"/"+global_pixel_scale[1]); + System.err.println("X11Screen: Env PixelScale: Env-Variable "+env_var_names[var_name_idx]); + System.err.println("X11Screen: Env PixelScale: Global: Set "+global_pixel_scale_set+", "+global_pixel_scale[0]+"/"+global_pixel_scale[1]); + System.err.println("X11Screen: Env PixelScale: Map: Set "+monitor_pixel_scale_map_set+", "+SurfaceScaleUtils.toString(monitor_pixel_scale_map)); } } else { + if( DEBUG ) { + System.err.println("X11Screen: Env PixelScale: None"); + } global_pixel_scale_set = false; + monitor_pixel_scale_map_set = false; } DisplayDriver.initSingleton(); @@ -138,10 +149,6 @@ public class ScreenDriver extends ScreenImpl { try { if( rAndR.beginInitialQuery(device.getHandle(), this) ) { try { - final float pixel_scale[] = { ScalableSurface.IDENTITY_PIXELSCALE, ScalableSurface.IDENTITY_PIXELSCALE }; - if( global_pixel_scale_set ) { - System.arraycopy(global_pixel_scale, 0, pixel_scale, 0, 2); - } final int[] crt_ids = rAndR.getMonitorDeviceIds(device.getHandle(), this); final int crtCount = null != crt_ids ? crt_ids.length : 0; @@ -178,6 +185,13 @@ public class ScreenDriver extends ScreenImpl { if( null != monitorProps && MonitorModeProps.MIN_MONITOR_DEVICE_PROPERTIES <= monitorProps[0] && // Enabled ? I.e. contains active modes ? MonitorModeProps.MIN_MONITOR_DEVICE_PROPERTIES <= monitorProps.length ) { + float pixel_scale[] = null; + if( monitor_pixel_scale_map_set && null != monitorName && !monitorName.isEmpty() ) { + pixel_scale = monitor_pixel_scale_map.get(monitorName); + } + if( null == pixel_scale && global_pixel_scale_set ) { + pixel_scale = global_pixel_scale; + } MonitorModeProps.streamInMonitorDevice(cache, this, crt_id, monitorName, pixel_scale, true /* invscale_wuviewport */, monitorProps, 0, null); } diff --git a/src/newt/classes/jogamp/newt/driver/x11/WindowDriver.java b/src/newt/classes/jogamp/newt/driver/x11/WindowDriver.java index 28f881bab..5fb01c619 100644 --- a/src/newt/classes/jogamp/newt/driver/x11/WindowDriver.java +++ b/src/newt/classes/jogamp/newt/driver/x11/WindowDriver.java @@ -108,6 +108,11 @@ public class WindowDriver extends WindowImpl { if( null != md ) { final float newPixelScale[] = { 0, 0 }; md.getPixelScale(newPixelScale); + if( DEBUG_IMPLEMENTATION ) { + System.err.println("Window.updatePixelScaleByMonitor: pixel "+getSurfaceBounds()+", window "+getBounds()); + System.err.println("Window.updatePixelScaleByMonitor: monitor "+md); + System.err.println("Window.updatePixelScaleByMonitor: has "+hasPixelScale[0]+", new "+newPixelScale[0]+" - "+getThreadName()); + } res = applySoftPixelScale(move_diff, sendEvent, defer, newPixelScale); } return res; diff --git a/src/test/com/jogamp/opengl/test/junit/newt/mm/TestScreenMode00aNEWT.java b/src/test/com/jogamp/opengl/test/junit/newt/mm/TestScreenMode00aNEWT.java index 78f59931a..a001383b8 100644 --- a/src/test/com/jogamp/opengl/test/junit/newt/mm/TestScreenMode00aNEWT.java +++ b/src/test/com/jogamp/opengl/test/junit/newt/mm/TestScreenMode00aNEWT.java @@ -110,20 +110,22 @@ public class TestScreenMode00aNEWT extends UITestCase { final long monitor_handle = -1; final int monitor_id = -1; + final String monitor_name = "DP-1"; final DimensionImmutable sizeMM = new Dimension(50, 50); final Rectangle viewport = new Rectangle(0, 0, 1920, 1080); final ArrayHashSet<MonitorMode> supportedModes = new ArrayHashSet<MonitorMode>(false, ArrayHashSet.DEFAULT_INITIAL_CAPACITY, ArrayHashSet.DEFAULT_LOAD_FACTOR); supportedModes.add(modeOut); - final MonitorDevice monOut = new MonitorDeviceImpl(null, monitor_handle, monitor_id, false, true, sizeMM, modeOut, null, viewport, viewport, supportedModes); + final MonitorDevice monOut = new MonitorDeviceImpl(null, monitor_handle, monitor_id, monitor_name, false, true, sizeMM, modeOut, null, viewport, viewport, supportedModes); System.err.println("01 out : "+monOut); cache.monitorDevices.add(monOut); { final int[] props = MonitorModeProps.streamOutMonitorDevice(monOut); - final MonitorDevice monIn = MonitorModeProps.streamInMonitorDevice(cache, null, monitor_handle, null, false /* invscale_wuviewport */, props, 0, null); + final MonitorDevice monIn = MonitorModeProps.streamInMonitorDevice(cache, null, monitor_handle, monitor_name, null, false /* invscale_wuviewport */, props, 0, null); System.err.println("01 in : "+monIn); Assert.assertEquals(monOut.getHandle(), monIn.getHandle()); Assert.assertEquals(monOut.getId(), monIn.getId()); + Assert.assertEquals(monOut.getName(), monIn.getName()); Assert.assertEquals(monOut.isClone(), monIn.isClone()); Assert.assertEquals(monOut.isPrimary(), monIn.isPrimary()); Assert.assertEquals(monOut.getViewport(), monIn.getViewport()); |