Add force_switch option to always write the input source - #206
Open
henrikosorensen wants to merge 2 commits into
Open
henrikosorensen wants to merge 2 commits into
henrikosorensen wants to merge 2 commits into
Conversation
display-switch reads a monitor's current input before writing, and skips the write if the monitor already reports the desired input. Some monitors report a stale input source when queried over a connection that is not the one currently being displayed: asked over DisplayPort 1 while actually displaying DisplayPort 2, they answer "DisplayPort 1". The write is then skipped and the monitor never switches. The failure is asymmetric, and shows up in the log as "is already set to" where "set to" is expected: switching away works, because the read happens to be accurate then, while switching back silently does nothing. Writes and reads do not fail together. On affected monitors DDC writes over an inactive input are delivered correctly, and only reads are unreliable, so always issuing the write is sufficient. "force_switch" defaults to false, leaving the read-before-write check in place for monitors that report their input correctly. Fixes haimgel#151 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
USB re-enumeration and the DDC write can race with each other, and the OS may still be re-enumerating displays when the USB event arrives, which can make switching intermittent. The sleep happens before enumerating displays rather than immediately before the write, so that display handles are acquired after the topology has settled rather than before. Defaults to 0, so behavior is unchanged unless the option is set. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Add
force_switchoption to always write the input sourceFixes #151.
Problem
try_switch_displayreads a monitor's current input before writing, and returns early if themonitor already reports the requested input. That optimization assumes the read is trustworthy.
On some monitors it isn't. Queried over a connection that is not the one currently being
displayed, they return a stale value: asked over DisplayPort 1 while actually displaying
DisplayPort 2, they answer
DisplayPort 1. display-switch concludes nothing needs to change andissues no write, so the monitor never switches.
The failure is asymmetric, which makes it confusing to diagnose. Switching away works — the
monitors really are on the current input then, so the read is accurate and the write proceeds.
Switching back silently does nothing. That is the direction that matters most.
Reproduced on 2× Acer XV273K (2019), Windows, direct GPU connection, with the second input driven
by a different machine. Log of a full round trip on stock v1.4.1:
At 15:59:31 both monitors were physically displaying DisplayPort 2. The read returned
0x0f.Worth being precise about the failure mode: the read does not error, time out, or return something
malformed. It returns a confident, well-formed, stale value. Retrying it or sleeping before it does
not help — there is nothing to wait for.
Why skipping the read is a valid fix
Reads and writes do not fail together on these monitors. With both monitors parked on DisplayPort 2
and actively displaying the other machine, writing the input source from the inactive connection
works reliably. Verified independently of display-switch, using ControlMyMonitor, which writes
unconditionally without reading first:
Both monitors switched immediately. So the DDC channel is functional on an inactive input for
writes; only reads are untrustworthy. Always issuing the write is therefore sufficient, and it is
the read — not the write — that has to be given up.
Changes
force_switch(defaultfalse) skips the read-before-write check and always issues the write.It is opt-in because the check is genuinely useful on monitors that report their input correctly:
it avoids redundant writes. Existing configurations are unaffected — there is a test asserting the
default.
A second commit adds
switch_delay_ms(default0), for setups where USB re-enumeration and theDDC write race. The sleep happens before enumerating displays rather than immediately before the
write, which is deliberate: it means display handles are acquired after the topology has settled
rather than before, so the delay also covers the OS still re-enumerating monitors. These two
options are independent — the force flag fixes a wrong assumption, the delay works around a
race. Happy to drop the second commit into its own PR, or drop it entirely, if you'd prefer.
Testing
cargo test— 14 pass, including new coverage for defaults, quoted ("true"), unquoted (true),and explicitly-disabled values.
cargo fmt --checkandcargo clippyclean for the changed files.log showing
set torather thanis already set toon every handle. Theinvalid DDC/CI lengthwarnings that this setup used to emit also disappear, since they camefrom the read path.
Notes
force_switchwould bedefensible — in a mixed setup only some panels misbehave — but it complicates
InputSourcesmerging, and the global flag is enough to fix the reported issue. Glad to extend it if you want.
Option<bool>/Option<u64>fields. These deserialize correctly through#[serde(flatten)]with the INI source, for quoted and unquoted values alike, which the testscover explicitly.
🤖 Generated with Claude Code