-
-
Save andrewmackrodt/89b6b998848f57b121cee68e580c4eb4 to your computer and use it in GitHub Desktop.
#!./node_modules/.bin/ts-node-dev | |
/** | |
* Based on https://askubuntu.com/a/1267328/170380 | |
*/ | |
import { exec } from 'child_process' | |
import dbus from 'dbus-next' | |
const sessionBus = dbus.sessionBus() | |
const main = async () => { | |
const namespace = 'org.gnome.Mutter.DisplayConfig' | |
const path = '/org/gnome/Mutter/DisplayConfig' | |
const proxyObject = await sessionBus.getProxyObject(namespace, path) | |
const clientInterface = proxyObject.getInterface(namespace) | |
let currentState = await clientInterface.GetCurrentState() | |
const [/* state */, connectedMonitors, logicalMonitors] = currentState | |
const logicalMonitor = logicalMonitors.find((monitor: any) => monitor[4] === true) | |
if ( ! logicalMonitor) { | |
throw new Error('Could not determine primary monitor') | |
} | |
let [x, y, scale, transform, primary, monitors] = logicalMonitor | |
const connector = monitors[0][0] | |
const connectedMonitor = connectedMonitors.find((monitor: any) => monitor[0][0] === connector) | |
if ( ! connectedMonitor) { | |
throw new Error('Could not determine connected monitor') | |
} | |
let currentMode: string | undefined | |
const displayModes = connectedMonitor[1] | |
for (const mode of displayModes) { | |
if (mode[6]['is-current']?.value) { | |
currentMode = mode[0] | |
break | |
} | |
} | |
if ( ! currentMode) { | |
throw new Error('Could not determine current display mode') | |
} | |
const execAsync = (command: string): Promise<string> => { | |
return new Promise((resolve, reject) => { | |
exec(command, (err, stdout, stderr) => { | |
if (stderr.length > 0) console.error(stderr) | |
if (err) { | |
reject(err) | |
} else { | |
resolve(stdout.replace(/\r?\n$/, '')) | |
} | |
}) | |
}) | |
} | |
const fractionalScalingKey = 'x11-randr-fractional-scaling' | |
const featuresText = await execAsync('gsettings get org.gnome.mutter experimental-features') | |
const featuresJson: string[] = JSON.parse(featuresText.replace(/^@as /, '').replace(/'/g, '"')) | |
if ( ! featuresJson.includes(fractionalScalingKey)) { | |
console.log('Enabling Mutter Experimental Feature:', fractionalScalingKey) | |
const value = JSON.stringify(featuresJson.concat(fractionalScalingKey)).replace(/"/g, '\'') | |
await execAsync(`gsettings set org.gnome.mutter experimental-features "${value}"`) | |
scale = 1.25 | |
} else { | |
console.log('Disabling Mutter Experimental Feature:', fractionalScalingKey) | |
const value = JSON.stringify(featuresJson.filter(v => v !== fractionalScalingKey)).replace(/"/g, '\'') | |
await execAsync(`gsettings set org.gnome.mutter experimental-features "${value}"`) | |
scale = 1 | |
} | |
const config = [[x, y, scale, transform, primary, [[connector, currentMode, {}]]]] | |
console.log('Applying Config:', JSON.stringify(config)) | |
// refresh current state as changing experimental-features invalidates previous serial | |
currentState = await clientInterface.GetCurrentState() | |
const serial = currentState[0] | |
await clientInterface.ApplyMonitorsConfig(serial, 1, config, {}) | |
} | |
main().finally(() => { | |
sessionBus.disconnect() | |
}) |
@jonathanbossenger I created a repository over at https://github.com/andrewmackrodt/gnome-scale-switcher
# clone repository and install dependencies
git clone https://github.com/andrewmackrodt/gnome-scale-switcher.git
cd gnome-scale-switcher
npm install
# run the application
npm start
You may want to edit index.ts
to match whatever resolution and scaling preferences you need the defaults (lines 9-21) are:
const fractionalModeSet: ModeSet = {
width: 3840,
height: 2160,
refresh: 60,
scale: 1.5,
}
const nonFractionalModeSet: ModeSet = {
width: 1920,
height: 1080,
refresh: 120,
scale: 1,
}
Please be warned, I find this to be unstable versus several months ago, I'm not sure if something has changed in the nvidia driver or with gnome/mutter - but sometimes during a resolution switch, the X display does not come back up, requiring a forceful reboot. This seems to happen when turning fractional scaling on/off and then setting the resolution before the display has "refreshed". To try and work around this I've hardcoded a sleep of 10 seconds between these operations.
Thanks, @andrewmackrodt I will check it out.
I just stumbled across this from here and it's exactly what I'm looking for. To run this, do I just save the js file, and then call it using node ie
node hidpi-switch.ts
?