Last active
May 9, 2026 00:53
-
-
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. Claude vibe coded so consider this public domain.
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 connection = Gio.bus_get_sync(Gio.BusType.SESSION, null); | |
| function dbusCall(method, params) { | |
| return connection.call_sync( | |
| BUS_NAME, BUS_PATH, BUS_NAME, | |
| method, params, null, | |
| Gio.DBusCallFlags.NONE, -1, null | |
| ); | |
| } | |
| function variant(signature, value) { | |
| return new GLib.Variant(signature, value); | |
| } | |
| function notify(message) { | |
| Gio.Subprocess.new( | |
| ['notify-send', '-a', 'HDR Toggle', message], | |
| Gio.SubprocessFlags.NONE | |
| ); | |
| } | |
| // recursiveUnpack (not deepUnpack) unwraps the per-monitor a{sv} variant containers. | |
| const [serial, monitors, displayLayouts, topLevelProps] = | |
| dbusCall('GetCurrentState', null).recursiveUnpack(); | |
| const monitorState = new Map(monitors.map(([[connector], modes, props]) => { | |
| // Fall back to first mode when none is marked current — a null mode_id throws opaquely. | |
| const currentMode = modes.find(m => m[6]['is-current'])?.[0] ?? modes[0]?.[0]; | |
| return [connector, { | |
| currentMode, | |
| colorMode: props['color-mode'] ?? ColorMode.SDR, | |
| supportedColorModes: props['supported-color-modes'] ?? [ColorMode.SDR], | |
| underscanning: 'underscanning' in props ? props['underscanning'] : undefined, | |
| }]; | |
| })); | |
| const hdrCapable = [...monitorState.values()].filter( | |
| m => m.supportedColorModes.includes(ColorMode.HDR) | |
| ); | |
| if (!hdrCapable.length) { | |
| notify('No HDR-capable monitors.'); | |
| imports.system.exit(1); | |
| } | |
| // Treat any non-zero color-mode as "on" so mode 2 (alt HDR variant) isn't toggled to mode 1. | |
| const targetColorMode = hdrCapable.some(m => m.colorMode === ColorMode.SDR) | |
| ? ColorMode.HDR | |
| : ColorMode.SDR; | |
| // ApplyMonitorsConfig signature a(iiduba(ssa{sv})) puts props inside each monitor tuple. | |
| const updatedLayouts = displayLayouts.map(([x, y, scale, transform, primary, displays]) => | |
| [x, y, scale, transform, primary, displays.map(([connector]) => { | |
| const m = monitorState.get(connector); | |
| const props = {}; | |
| if (m.underscanning !== undefined) | |
| props['underscanning'] = variant('b', m.underscanning); | |
| if (m.supportedColorModes.includes(ColorMode.HDR)) | |
| props['color-mode'] = variant('u', targetColorMode); | |
| return [connector, m.currentMode, props]; | |
| })] | |
| ); | |
| const applyProps = {}; | |
| if (topLevelProps['layout-mode'] !== undefined) | |
| applyProps['layout-mode'] = variant('u', topLevelProps['layout-mode']); | |
| dbusCall('ApplyMonitorsConfig', | |
| variant('(uua(iiduba(ssa{sv}))a{sv})', [serial, 2, updatedLayouts, applyProps]) | |
| ); | |
| 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