diff --git a/dylib/feats/compat_run.sh b/dylib/feats/compat_run.sh index 3f4c93bb..b691f645 100755 --- a/dylib/feats/compat_run.sh +++ b/dylib/feats/compat_run.sh @@ -1171,7 +1171,7 @@ if [ "$verb" = waitforexitandrun ] && [ -f "$np_defaults_file" ] && [ -r "$np_de FEX_X87REDUCEDPRECISION=[01]) [ "${wine_unix##*/}" = aarch64-unix ] || continue ;; MTL_HUD_ENABLED=[01] | DXMT_ENABLE_NVEXT=[01] | DXMT_METALFX_SPATIAL_SWAPCHAIN=[01] | \ - WINEMSYNC=[01] | NOTPROTON_RETINA=[01] | NOTPROTON_RAW_CONTROLLERS=[01] | NOTPROTON_DISABLE_HIDRAW=[01]) ;; + WINEMSYNC=[01] | NOTPROTON_RETINA=[01] | NOTPROTON_RETINA_DPI=[01] | NOTPROTON_RAW_CONTROLLERS=[01] | NOTPROTON_DISABLE_HIDRAW=[01]) ;; DXMT_CONFIG=*\;*) dxmt_added="" old_ifs=$IFS; IFS=";" diff --git a/dylib/feats/defaults.c b/dylib/feats/defaults.c index e1998b07..385071d3 100644 --- a/dylib/feats/defaults.c +++ b/dylib/feats/defaults.c @@ -37,6 +37,7 @@ static const struct { { "ROSETTA_ADVERTISE_AVX", ROSETTA, "", g_bools, NULL }, { "WINEMSYNC", ROSETTA | FEX, "", g_bools, NULL }, { "NOTPROTON_RETINA", ROSETTA | FEX, "", g_bools, NULL }, + { "NOTPROTON_RETINA_DPI", ROSETTA | FEX, "", g_bools, NULL }, { "DXMT_METALFX_SPATIAL_SWAPCHAIN", ROSETTA | FEX, "", g_bools, NULL }, { "DXMT_CONFIG", ROSETTA | FEX, "d3d11.metalSpatialUpscaleFactor=", g_factors, NULL }, { "NOTPROTON_RAW_CONTROLLERS", ROSETTA | FEX, "", g_bools, NULL }, diff --git a/dylib/feats/webpatch.c b/dylib/feats/webpatch.c index a0d004a8..22031986 100644 --- a/dylib/feats/webpatch.c +++ b/dylib/feats/webpatch.c @@ -1395,7 +1395,10 @@ static int out_expand(np_out_t *o, const char *replace, const np_cap_t *caps) { "\"dxmt\"===b&&T(\"DXMT_ENABLE_NVEXT\",\"DLSS\")," \ "!fex&&D(\"ROSETTA_ADVERTISE_AVX\",npL(\"Advertise AVX2 to Rosetta\",\"向 Rosetta 声明 AVX2 支持\",\"Segnala AVX2 a Rosetta\"))," \ "T(\"WINEMSYNC\",\"MSync\")," \ - "T(\"NOTPROTON_RETINA\",npL(\"High Resolution\",\"高分辨率\",\"Alta risoluzione\"))" \ + "T(\"NOTPROTON_RETINA\",npL(\"High Resolution\",\"高分辨率\",\"Alta risoluzione\"))," \ + /* On writes 0, the run script's opt-out, and off writes 1 only to beat a default of 0. */ \ + "(0," RT ".jsx)(" BARREL ".Yh,{className:\"MSCXRow\",label:npL(\"Don't Scale Windows DPI (Fixes games that only offer low resolutions when High Resolution is on)\",\"Don't Scale Windows DPI (Fixes games that only offer low resolutions when High Resolution is on)\",\"Don't Scale Windows DPI (Fixes games that only offer low resolutions when High Resolution is on)\")," \ + "checked:\"0\"===G(\"NOTPROTON_RETINA_DPI\"),onChange:v=>s([[\"NOTPROTON_RETINA_DPI\",w(\"NOTPROTON_RETINA_DPI\",v?\"0\":\"1\",\"1\")]])},\"NOTPROTON_RETINA_DPI\")" \ "]},\"gfx\")," \ "ours&&dx&&(0," RT ".jsx)(" BARREL ".XY," \ "{label:npL(\"MetalFX Upscaling (Samples from the resolution the game is set to)\"," \ diff --git a/dylib/tests/panel-behavior/behavior.js b/dylib/tests/panel-behavior/behavior.js index 52025745..a7973f4c 100644 --- a/dylib/tests/panel-behavior/behavior.js +++ b/dylib/tests/panel-behavior/behavior.js @@ -128,7 +128,7 @@ for (const form of Object.keys(FORMS)) { } let r = nodes(''); - t.ok(toggles(r).length === 7 && sections(r).length === 5, 'automatic shows seven toggles in five sections'); + t.ok(toggles(r).length === 8 && sections(r).length === 5, 'automatic shows eight toggles in five sections'); t.ok(r.filter(x => x.type === 'Dropdown').length === 3, 'three dropdowns'); t.ok(!('label' in r.find(x => x.type === 'Dropdown').props), 'the backend dropdown carries no label column'); @@ -216,13 +216,21 @@ for (const form of Object.keys(FORMS)) { const root = P({ details: details('') }); t.ok(root.props.className === 'MSCXPanel', 'the panel root carries its own class'); const classes = nodes('').filter(x => x.type === 'Toggle').map(x => x.props.className); - t.ok(classes.length === 7 && classes.every(c => c === 'MSCXRow'), 'every checkbox carries the row class'); + t.ok(classes.length === 8 && classes.every(c => c === 'MSCXRow'), 'every checkbox carries the row class'); const raw = o => nodes(o).find(x => x.props.label === 'Let Games Read Controllers Directly (May break Steam Input. Not recommended)'); t.ok(sections(nodes('')).includes('Controllers') && raw('').props.checked === false, 'controller hiding is on unless the game says otherwise'); written.length = 0; nodes('').find(x => x.props.label === 'Disable hidraw').props.onChange(true); t.ok(last().trim() === 'NOTPROTON_DISABLE_HIDRAW=1 %command%', `hidraw (${last()})`); + const dpi = o => nodes(o).find(x => x.props.label === "Don't Scale Windows DPI (Fixes games that only offer low resolutions when High Resolution is on)"); + t.ok(dpi('').props.checked === false && dpi('NOTPROTON_RETINA_DPI=0').props.checked === true, 'the DPI row reads the opt-out'); + written.length = 0; + dpi('').props.onChange(true); + t.ok(last().trim() === 'NOTPROTON_RETINA_DPI=0 %command%', `the DPI row writes the opt-out (${last()})`); + written.length = 0; + dpi('NOTPROTON_RETINA_DPI=0 WINEMSYNC=1').props.onChange(false); + t.ok(last().trim() === 'WINEMSYNC=1 %command%', `turning the DPI row off removes it (${last()})`); written.length = 0; raw('').props.onChange(true); t.ok(last().trim() === 'NOTPROTON_RAW_CONTROLLERS=1 %command%', `the controller row writes its flag (${last()})`);