feat(displaycontrol): let a server handler override its capabilities - #1917
Greg Lamberson (glamberson) wants to merge 4 commits into
Conversation
DisplayControlServer::start() hardcoded DisplayControlCapabilities::new(1, 3840, 2400), giving every server a fixed single-monitor cap with no way to advertise more. Added a default trait method mirroring the existing monitor_layout() pattern, so a handler serving multiple monitors can override it; anything that doesn't override it keeps today's exact behavior.
There was a problem hiding this comment.
🟢 Approval recommended
The implementation is sound; the only unresolved comment is a non-blocking documentation nit.
Pull request overview
Enables display-control handlers to customize advertised monitor capabilities while preserving existing defaults.
Changes:
- Adds an overridable
capabilities()method. - Uses handler-provided capabilities during startup.
File summaries
| File | Review |
|---|---|
crates/ironrdp-displaycontrol/src/server.rs |
Capability customization is additive. Minor documentation issue: the example must handle the DecodeResult returned by DisplayControlCapabilities::new(...). |
Review details
Suppressed comments (1)
crates/ironrdp-displaycontrol/src/server.rs:20
DisplayControlCapabilities::new(...)returns aDecodeResult, so the documented expression cannot be returned directly from this method. Avoid presenting it as a valid return expression unless the validation result is handled explicitly.
/// A handler serving more than one monitor should override this to
/// return `DisplayControlCapabilities::new(monitor_count, 3840, 2400)`.
- Files reviewed: 1/1 changed files
- Comments generated: 0
- Review effort level: Balanced
…edback Removes the today and current framing CBenoit flagged as unnecessary historical wording, and fixes the override example to show the DecodeResult being unwrapped, matching what the default implementation already does.
There was a problem hiding this comment.
Additive, well-scoped change: DisplayControlServer::start() now takes the DISPLAYCONTROL_CAPS_PDU contents from a new defaulted DisplayControlHandler::capabilities() instead of a hardcoded (1, 3840, 2400) literal. I verified the default stays within the crate's internal limits (MAX_SUPPORTED_MONITORS 1024, MAX_MONITOR_AREA_FACTOR 16384 in pdu/mod.rs), so its expect never fires and the encoded PDU is byte-identical to before; non-overriding implementors are unaffected, and the hook mirrors the existing monitor_layout() and egfx preferred_capabilities() patterns. One merged issue (three duplicate specialist findings): the infallible signature deletes start()'s decode_err! error path and the doc example encourages .expect, so an override built from runtime state that exceeds the crate limits panics during channel start; a Result-returning hook would preserve error propagation. No other correctness, protocol, or maintainability concerns found.
… error capabilities() was declared infallible, so the only way an overrider could report invalid values (a monitor count or area factor combination DisplayControlCapabilities::new rejects) was to panic. That panic runs inside start(), a DvcProcessor callback, and unwinds through it rather than surfacing as a recoverable PduResult::Err. The trait method now returns PduResult<DisplayControlCapabilities>, and start() propagates via the same decode_err! conversion process() already uses. Adds a regression test exercising start() with an out-of-range override.
There was a problem hiding this comment.
Additive and correct. DisplayControlHandler::capabilities() defaults to DisplayControlCapabilities::new(1, 3840, 2400), reproducing the previous hardcoded start() output exactly, so the sole in-repo implementor (ironrdp-server's DisplayControlBackend, which does not override) is unaffected. start() propagates handler errors via the same decode_err! bridge process() uses; validation bounds in calculate_monitor_area are unchanged and one spec-conformant CAPS PDU is still sent at channel start. The doc comment accurately explains the fallibility and panic-abort risk. The added error-path test compiles against existing test dependencies and asserts real behavior. Changelog updates are automated via release-plz/git-cliff, so no manual CHANGELOG edit is expected. One low-severity gap remains: no test verifies a valid override's values reach the encoded start message, the error assertion does not check the error kind, and the default output stays untested.
The PR's core claim is that a handler can override capabilities() to advertise more than one monitor, but nothing verified a valid override's values were actually encoded into the DISPLAYCONTROL_CAPS_PDU returned by DisplayControlServer::start(). The one existing test only asserted that an invalid override errors, proving handler invocation and error propagation but not correct encoding. Added a positive-path test overriding capabilities() to (2, 3840, 2400) and decoding the resulting DVC message back to confirm the values reach the wire, plus a test pinning the default (1, 3840, 2400) capabilities() impl, which predates this PR as a hardcoded start() literal and was never covered by a test either.
|
Hi Greg Lamberson (@glamberson) |
|
Oops! I hadn't pushed that commit yet. Just pushed 3bb21ee, which adds the two tests: One confirming a multi-monitor override actually encodes into the DISPLAYCONTROL_CAPS_PDU, the other pinning the default (1, 3840, 2400) capabilities that predate this PR. All xtask gates pass. Thanks for catching it. |
|
This pull request may overlap with #1918. Both PRs center on the same DISPLAYCONTROL capabilities extension point: this PR adds the fallible, overridable DisplayControlHandler::capabilities() in ironrdp-displaycontrol, while This notice is advisory only. Automated review continues as usual, and how these pull requests relate is for maintainers and authors to decide. Note LLM-assisted content (no human feedback). |
Summary
DisplayControlServer::start()sendsDisplayControlCapabilities::new(1, 3840, 2400)unconditionally, so every server using this crate is capped at one monitor with no way to advertise more.DisplayControlHandler,capabilities(), thatstart()now calls instead of the hardcoded literal.(1, 3840, 2400)values, so any existing implementation that does not override it keeps its current behavior unchanged.capabilities()to report the real count.Validation
cargo xtask check fmt/lints/tests/typos/locksall pass.Notes
start(). No existing implementor is affected unless it opts in.