Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 1 addition & 72 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 1 addition & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,12 @@ winres = "0.1"
[dependencies]
ddc = "0.2"
ddc-winapi = "0.2"
display-info = "0.4"
global-hotkey = "0.8"
thiserror = "2.0"
tokio = { version = "1", features = ["full"] }
tokio = { version = "1", features = ["rt", "time", "sync", "macros"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
dirs = "6.0"
futures-util = "0.3"
log = "0.4"
env_logger = "0.11"
tray-icon = "0.25"
Expand Down
24 changes: 18 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,34 +4,42 @@
[![Latest release](https://img.shields.io/github/v/release/cyb0rg56/WinDisplayManager)](https://github.com/cyb0rg56/WinDisplayManager/releases/latest)
[![MIT license](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)

DDC/CI monitor control for Windows — brightness, contrast, input switching,
DDC/CI monitor control for Windows: brightness, contrast, input switching,
power mode, hotkeys, and display profiles, all from a native GUI.

📖 Full docs and download links: **https://cyb0rg56.github.io/WinDisplayManager/**

## Features

- **Brightness & contrast control** over DDC/CI, per monitor.
- **Input source switching** (HDMI, DisplayPort, etc.) with a click or a hotkey.
- **Power mode control** to put a monitor to sleep or wake it from the app.
- **Global hotkeys** with configurable *action chains* — one shortcut can run
- **Input source switching** (HDMI, DisplayPort, etc.) from the monitor page
or a hotkey, using the inputs each monitor advertises.
- **Power mode control** to put monitors into standby or turn them off with a
hotkey, or sleep all displays from the tray.
- **Global hotkeys** with configurable *action chains*: one shortcut can run
several actions at once (set or offset brightness/contrast, switch inputs,
change power mode, write custom DDC/CI VCP codes, apply a profile, or turn
displays off), each targeting all displays or specific monitors. Configurable
entirely in-app.
- **Display profiles** to save and restore whole monitor layouts (resolution, position, orientation) via Windows CCD, switchable instantly or by hotkey.
- **System tray integration** which lives quietly in the tray, always one click away.
- **System tray integration**: closing the window keeps the app in the tray,
with quick access to profiles and turning displays off. Optionally starts
with Windows, minimized to the tray.
- **Native GUI** built with [libcosmic](https://github.com/pop-os/libcosmic)/[iced](https://github.com/iced-rs/iced).

## Installation

Download the latest `windisplaymanager_rs-*.exe` from the
[Releases page](https://github.com/cyb0rg56/WinDisplayManager/releases/latest)
and run it — it's a single portable executable, no installer needed.
and run it. It's a single portable executable, no installer needed.

> The executable isn't code-signed, so Windows SmartScreen may warn you on
> first run. Click **More info → Run anyway** to proceed.

Monitors must have **DDC/CI** enabled in their on-screen menu. Settings are
stored in `%APPDATA%\windisplaymanager\config.json`; see
[Configuration & recovery](https://cyb0rg56.github.io/WinDisplayManager/docs/configuration/).

## Building from source

Requires a recent stable Rust toolchain (edition 2024) on Windows.
Expand All @@ -46,8 +54,12 @@ To publish a GitHub Release, tag `v` plus the `Cargo.toml` version and push that

## Documentation

- [Monitors guide](https://cyb0rg56.github.io/WinDisplayManager/docs/monitors/)
- [Hotkeys guide](https://cyb0rg56.github.io/WinDisplayManager/docs/hotkeys/)
- [Profiles guide](https://cyb0rg56.github.io/WinDisplayManager/docs/profiles/)
- [Settings & startup](https://cyb0rg56.github.io/WinDisplayManager/docs/settings/)
- [Configuration & recovery](https://cyb0rg56.github.io/WinDisplayManager/docs/configuration/)
- [Troubleshooting & FAQ](https://cyb0rg56.github.io/WinDisplayManager/docs/troubleshooting/)
- [Testing](https://cyb0rg56.github.io/WinDisplayManager/docs/testing/)
- [Privacy policy](https://cyb0rg56.github.io/WinDisplayManager/privacy/)

Expand Down
6 changes: 5 additions & 1 deletion docs/astro.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export default defineConfig({
starlight({
title: 'WinDisplayManager',
description:
'DDC/CI monitor control for Windows — brightness, contrast, input switching, power mode, hotkeys, and display profiles.',
'DDC/CI monitor control for Windows: brightness, contrast, input switching, power mode, hotkeys, and display profiles.',
social: [
{
icon: 'github',
Expand All @@ -52,8 +52,12 @@ export default defineConfig({
],
sidebar: [
{ label: 'Home', slug: 'index' },
{ label: 'Monitors', slug: 'docs/monitors' },
{ label: 'Hotkeys', slug: 'docs/hotkeys' },
{ label: 'Profiles', slug: 'docs/profiles' },
{ label: 'Settings & startup', slug: 'docs/settings' },
{ label: 'Configuration & recovery', slug: 'docs/configuration' },
{ label: 'Troubleshooting', slug: 'docs/troubleshooting' },
{ label: 'Testing', slug: 'docs/testing' },
{ label: 'Privacy', slug: 'privacy' },
],
Expand Down
124 changes: 124 additions & 0 deletions docs/src/content/docs/docs/configuration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
---
title: Configuration & recovery
description: Where WinDisplayManager stores its settings, the file format, backups, and how to recover a damaged configuration.
---

All settings are stored per user under `%APPDATA%` (your roaming application
data folder). Nothing is written next to the executable.

| What | Location |
|---|---|
| Settings and hotkeys | `%APPDATA%\windisplaymanager\config.json` |
| Previous settings | `%APPDATA%\windisplaymanager\config.json.bak` |
| Display profiles | `%APPDATA%\MonitorSwitcher\Profiles\<name>.json` |
| Start with Windows | `HKCU\Software\Microsoft\Windows\CurrentVersion\Run`, value `WindowsDisplayManager` |

The **About** page shows the full path of the configuration file, with a
**Copy** button.

## What gets saved when

- The **Save** icon in the header writes hotkeys, labels, actions and the
power-off method. It is highlighted while there are unsaved changes.
- **Start with Windows**, **Start minimized** and **Enable global hotkeys** are
saved as soon as you toggle them. Saving writes the whole configuration, so
any unsaved hotkey edits are written at the same time.
- Profiles are written when you save or replace them, independently of
`config.json`.

If `config.json` doesn't exist yet, the app starts with defaults and creates
the file the first time something is saved.

## File format

`config.json` is plain, indented JSON:

```json
{
"schema_version": 1,
"hotkeys": {
"hotkeys": [
{
"id": "hk-…",
"label": "Dim everything",
"binding": { "ctrl": true, "alt": true, "shift": false, "win": false, "key": "F1" },
"actions": [
{
"action_type": "Offset",
"target": "Brightness",
"all_monitors": true,
"monitors": [],
"value": -10,
"vcp_code": 16,
"input_source": "Hdmi1",
"monitor_inputs": [],
"power_mode": "On",
"profile_name": ""
}
]
}
],
"brightness_step": 10,
"contrast_step": 10
},
"hotkeys_enabled": true,
"turn_off_behavior": "None",
"start_with_windows": false,
"start_minimized": false
}
```

| Field | Default | Notes |
|---|---|---|
| `schema_version` | `1` | Files without it are treated as older versions and upgraded when loaded. |
| `hotkeys.hotkeys` | `[]` | See the [Hotkeys guide](/docs/hotkeys/). |
| `hotkeys_enabled` | `true` | *Enable global hotkeys* in Settings. |
| `turn_off_behavior` | `"None"` | `"None"`, `"Soft"`, `"Ddc"` or `"Both"`. |
| `start_with_windows` | `false` | Mirrors the registry `Run` value. |
| `start_minimized` | `false` | Kept even when startup is off. |

Monitor selections in `monitors` and `monitor_inputs` are Windows device paths
(`windows-device-path:v1:\\?\display#…`). A plain number is an old,
[legacy selection](/docs/hotkeys/#migrating-monitor-selections) that needs
rebinding. You normally don't need to edit the file by hand; if you do, exit
the app first so your edits aren't overwritten.

## Backups

Every save first copies the current, valid `config.json` to
`config.json.bak`, then replaces the file in one step, so a crash or power
loss mid-save leaves either the old or the new file, never a half-written
one. Profiles work the same way: replacing a profile keeps the previous
version as `<name>.json.bak`.

The app never overwrites a file it can't read. If `config.json` is damaged,
ordinary saves are refused rather than replacing it.

## Recovering a damaged configuration

If `config.json` can't be read (invalid JSON, a newer `schema_version` from a
later release, or a permissions problem), the app shows
**Configuration recovery required** at the top of every page, with the file
path and the error. Until you resolve it:

- Global hotkeys are disabled, and the Hotkeys page shows only the recovery
panel.
- Settings and hotkey edits are blocked, and nothing is written to
`config.json`.
- Your Start with Windows registration is left as it was.
- Monitor controls and profiles keep working.

Choose one of:

| Button | What it does |
|---|---|
| **Retry loading** | Reads `config.json` again. Use this after fixing the file by hand or restoring a copy. |
| **Recover backup** | Loads `config.json.bak` and writes it back as `config.json`. The backup is kept. |
| **Reset to defaults…** | After you click **Confirm reset**, replaces `config.json` with defaults. This discards your hotkeys; the backup is kept. |

Before resetting, consider copying the damaged file somewhere safe: it may
still contain hotkeys you can re-create.

A file with a newer `schema_version` usually means you ran a newer release and
then went back to an older one. Upgrade again instead of resetting, or use
**Recover backup** if the backup was written by this version.
Loading
Loading