-
-
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 startYou 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?