Last active
October 2, 2026 04:55
-
-
Save JamesMcMahon/c815a2d9bc8117a6dbebbf2cc9b9644e to your computer and use it in GitHub Desktop.
HDR Toggle for Gnome - can be assigned to shortcut and run via gjs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/gjs | |
| const {GLib, Gio} = imports.gi; | |
| const BUS_NAME = 'org.gnome.Mutter.DisplayConfig'; | |
| const BUS_PATH = '/org/gnome/Mutter/DisplayConfig'; | |
| const ColorMode = {SDR: 0, HDR: 1}; | |
| const PERSISTENT = 2; | |
| const connection = Gio.bus_get_sync(Gio.BusType.SESSION, null); | |
| const dbusCall = (method, params) => | |
| connection.call_sync( | |
| BUS_NAME, BUS_PATH, BUS_NAME, | |
| method, params, null, | |
| Gio.DBusCallFlags.NONE, -1, null | |
| ); | |
| const notify = message => { | |
| Gio.Subprocess.new( | |
| ['notify-send', '-a', 'HDR Toggle', message], | |
| Gio.SubprocessFlags.NONE | |
| ); | |
| }; | |
| // recursiveUnpack unwraps the values inside Mutter's a{sv} dictionaries. | |
| const [serial, monitors, displayLayouts, topLevelProps] = | |
| dbusCall('GetCurrentState', null).recursiveUnpack(); | |
| // Mode tuples contain the ID at index 0 and properties at index 6. | |
| const monitorsByConnector = new Map(monitors.map(([[connector], modes, props]) => { | |
| const modeId = modes.find(mode => mode[6]['is-current'] === true)?.[0] ?? modes[0]?.[0]; | |
| return [connector, { | |
| modeId, | |
| colorMode: props['color-mode'] ?? ColorMode.SDR, | |
| hdrCapable: (props['supported-color-modes'] ?? []).includes(ColorMode.HDR), | |
| underscanning: props['underscanning'], | |
| }]; | |
| })); | |
| const monitorsWithoutMode = [...monitorsByConnector] | |
| .filter(([, monitor]) => monitor.modeId == null) | |
| .map(([connector]) => connector); | |
| if (monitorsWithoutMode.length > 0) { | |
| notify(`Could not determine a display mode for: ${monitorsWithoutMode.join(', ')}`); | |
| imports.system.exit(1); | |
| } | |
| const hdrMonitors = [...monitorsByConnector.values()].filter(monitor => monitor.hdrCapable === true); | |
| if (hdrMonitors.length === 0) { | |
| notify('No HDR-capable monitors.'); | |
| imports.system.exit(1); | |
| } | |
| // Any non-SDR mode (including mode 2) counts as HDR being on. | |
| const targetColorMode = hdrMonitors.some(monitor => monitor.colorMode === ColorMode.SDR) | |
| ? ColorMode.HDR | |
| : ColorMode.SDR; | |
| // ApplyMonitorsConfig takes per-monitor properties, unlike GetCurrentState. | |
| const updatedLayouts = displayLayouts.map(([x, y, scale, transform, primary, displays]) => | |
| [x, y, scale, transform, primary, displays.map(([connector]) => { | |
| const monitor = monitorsByConnector.get(connector); | |
| const props = {}; | |
| if (monitor.underscanning !== undefined) { | |
| props['underscanning'] = new GLib.Variant('b', monitor.underscanning); | |
| } | |
| if (monitor.hdrCapable === true) { | |
| props['color-mode'] = new GLib.Variant('u', targetColorMode); | |
| } | |
| return [connector, monitor.modeId, props]; | |
| })] | |
| ); | |
| const applyProps = {}; | |
| if (topLevelProps['layout-mode'] !== undefined) { | |
| applyProps['layout-mode'] = new GLib.Variant('u', topLevelProps['layout-mode']); | |
| } | |
| dbusCall('ApplyMonitorsConfig', | |
| new GLib.Variant('(uua(iiduba(ssa{sv}))a{sv})', [serial, PERSISTENT, updatedLayouts, applyProps]) | |
| ); | |
| const nightLight = new Gio.Settings({schema_id: 'org.gnome.settings-daemon.plugins.color'}); | |
| const stateDir = GLib.get_user_state_dir(); | |
| const nightLightMarker = GLib.build_filenamev([stateDir, 'hdr-toggle-night-light']); | |
| if (targetColorMode === ColorMode.HDR && nightLight.get_boolean('night-light-enabled') === true) { | |
| GLib.mkdir_with_parents(stateDir, 0o700); | |
| GLib.file_set_contents(nightLightMarker, ''); | |
| nightLight.set_boolean('night-light-enabled', false); | |
| } else if (targetColorMode === ColorMode.SDR && | |
| GLib.file_test(nightLightMarker, GLib.FileTest.EXISTS) === true) { | |
| if (nightLight.set_boolean('night-light-enabled', true) === true) { | |
| GLib.unlink(nightLightMarker); | |
| } | |
| } | |
| notify(`HDR ${targetColorMode === ColorMode.HDR ? 'enabled' : 'disabled'}`); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment