Skip to content

feat(viewer): run RemoteApp programs in native windows - #2201

Merged
Marc-André Moreau (mamoreau-devolutions) merged 2 commits into
masterfrom
claude/remoteapp-viewer
Oct 23, 2026
Merged

Marc-André Moreau (mamoreau-devolutions) merged 2 commits into
masterfrom
claude/remoteapp-viewer

Conversation

@mamoreau-devolutions

@mamoreau-devolutions Marc-André Moreau (mamoreau-devolutions) commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

The viewer could only show a full desktop; it ignored the RemoteApp settings and dropped windowing orders.

--remote-app (or remoteapplicationmode and remoteapplicationprogram in an .rdp file) starts a RemoteApp session without a desktop window. Each server window becomes an undecorated local window that follows the window orders: position, size, title, show state, owner and taskbar visibility, and its icon. Windows are painted from their rectangle of the session frame, or from the graphics pipeline surface the server maps to them. Keyboard, mouse and wheel input are translated into session coordinates; focus changes send Activate and closing a window asks the server with a Close system command. The server's active window is focused when a RemoteApp window already has focus.

Program arguments, the working directory, notification icons, z-order, local move/size and window shapes are not handled yet.

🤖 Generated with Claude Code

@mamoreau-devolutions

Copy link
Copy Markdown
Contributor Author

Line counts: production code about +300/−166 (new rail.rs and the RemoteApp branch in app.rs; the key, modifier, wheel and button mapping moved into shared helpers so the desktop window behaves as before); tests +168 in ironrdp-testsuite-extra/tests/client/viewer_rail.rs (window model merging, coordinate translation, frame cropping, surface updates, icon conversion); manifests and lockfile +3 (ironrdp-rail, which the meta crate does not re-export).

Not run against a server yet.

@github-actions github-actions Bot added kind/protocol Affects RDP or related protocol behavior risk/medium Behavioral change that does not substantially alter a core public API size/XL Size: up to 1299 counted lines and 49 files; exceeds L in either measure triage/overlap Possible overlap with another pull request; advisory only labels Oct 22, 2026
@github-actions github-actions Bot added the breaking-change Includes a breaking change, and requires special scrutiny at the boundaries label Oct 22, 2026

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR adds RemoteApp (RAIL) support to the viewer: server windows become local winit windows fed from the session frame or mapped graphics surfaces, with Activate/Close PDUs and translated input. I independently verified the window-order handling, model merging, coordinate translation, frame cropping and icon decoding in rail.rs, the input wiring in app.rs, and the cited line ranges against pr-head. The change is well scoped and the desktop input path is a faithful extraction into shared helpers. All 18 specialist candidates check out on inspection; none has an incorrect root cause, so all are accepted unchanged. The material concerns are the public API surface added solely for external tests, the focus-loss path releasing only modifier keys, style/owner/taskbar attributes that are write-only after window creation, icons dropped when their window order has not arrived yet, and several testability gaps. The rest are mechanical style and compression nits.

Push a commit after addressing these findings. If no code change is needed, you may resolve inline threads and comment @github-actions review-ready to request human review.

#[cfg(windows)]
pub mod drives;
mod keymap;
pub mod rail;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[skeptical] `rail` module made public API solely for external tests — medium 🟠 — `pub mod rail` exposes RailWindowModel with public fields, ModelChanges, WindowPixels, crop_frame, window_point_to_desktop, icon_to_rgba and MAX_RAIL_WINDOWS as public API of the published viewer crate. The only external consumer is the new integration test in ironrdp-testsuite-extra/tests/client/viewer_rail.rs, which reads model.title/model.x directly; no other crate uses these items and the viewer keeps `keymap` private (lib.rs:16). Placing the same tests as a unit-test module inside rail.rs would test identical behavior without committing the crate to a public, must-maintain surface of internal pixel/window-model helpers.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Declined. Kept public on purpose: AGENTS.md puts tests in ironrdp-testsuite-extra and the viewer library builds with test = false, so the helpers must be reachable from there, as cli and drives already are. The exposed items are the pure model and pixel helpers; the window manager itself stays crate-private.

Comment thread crates/ironrdp-viewer/src/app.rs
Comment thread crates/ironrdp-viewer/src/rail.rs Outdated
Comment thread crates/ironrdp-viewer/src/rail.rs
Comment thread crates/ironrdp-viewer/src/rail.rs
Comment thread crates/ironrdp-viewer/src/rail.rs Outdated
Comment thread crates/ironrdp-viewer/src/app.rs Outdated
Comment thread crates/ironrdp-viewer/src/rail.rs Outdated
Comment thread crates/ironrdp-viewer/src/app.rs Outdated
Comment thread crates/ironrdp-viewer/src/rail.rs
@github-actions github-actions Bot added ai-reviewed/1 One automated review completed needs-author-action The pull request author is the current next actor labels Oct 22, 2026
@github-actions github-actions Bot added size/XXL Size: 1300 or more counted lines or 50 or more files and removed needs-author-action The pull request author is the current next actor size/XL Size: up to 1299 counted lines and 49 files; exceeds L in either measure breaking-change Includes a breaking change, and requires special scrutiny at the boundaries labels Oct 22, 2026
@github-actions github-actions Bot added automation-failed Exact-head automated classification or review failed or was unavailable risk/unknown Risk could not be determined automatically; needs maintainer-level scrutiny and removed risk/medium Behavioral change that does not substantially alter a core public API labels Oct 22, 2026
@github-actions github-actions Bot added the needs-author-action The pull request author is the current next actor label Oct 23, 2026
@github-actions github-actions Bot added breaking-change Includes a breaking change, and requires special scrutiny at the boundaries needs-review A human reviewer is the current next actor and removed needs-author-action The pull request author is the current next actor labels Oct 23, 2026
@github-actions github-actions Bot added needs-review A human reviewer is the current next actor and removed needs-review A human reviewer is the current next actor breaking-change Includes a breaking change, and requires special scrutiny at the boundaries labels Oct 23, 2026
@github-actions github-actions Bot removed the needs-review A human reviewer is the current next actor label Oct 23, 2026
@github-actions github-actions Bot added the needs-review A human reviewer is the current next actor label Oct 23, 2026
@github-actions github-actions Bot added needs-review A human reviewer is the current next actor and removed needs-review A human reviewer is the current next actor labels Oct 23, 2026
Base automatically changed from claude/remoteapp-egfx-windows to master October 23, 2026 19:20
The viewer could only show a full desktop; it ignored the RemoteApp
settings and dropped windowing orders.

--remote-app (or remoteapplicationmode and remoteapplicationprogram in
an .rdp file) starts a RemoteApp session without a desktop window. Each
server window becomes an undecorated local window that follows the
window orders: position, size, title, show state, owner and taskbar
visibility, and its icon. Windows are painted from their rectangle of
the session frame, or from the graphics pipeline surface the server
maps to them. Keyboard, mouse and wheel input are translated into
session coordinates; focus changes send Activate and closing a window
asks the server with a Close system command. The server's active window
is focused when a RemoteApp window already has focus.

Program arguments, the working directory, notification icons, z-order,
local move/size and window shapes are not handled yet.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Unbounded rendering allocations, native ownership handling, and dropped input during queue saturation leave significant correctness and reliability issues.

6 open issues
What changed in this PR

Adds native RemoteApp windows to the viewer, using the client’s windowing orders and graphics output instead of displaying a full desktop.

Changes:

  • Adds RemoteApp CLI configuration and starts RemoteApp sessions without a desktop window.
  • Creates and paints per-application windows, forwards input, and sends activation and close commands.
  • Adds tests for window models, coordinate translation, pixel cropping, icons, and graphics-buffer budgets.
File Description
crates/​ironrdp-viewer/​src/​rail.rs Implements RemoteApp window management, rendering, and icons.
crates/​ironrdp-viewer/​src/​main.rs Passes RemoteApp mode into viewer initialization.
crates/​ironrdp-viewer/​src/​lib.rs Exposes the RemoteApp module.
crates/​ironrdp-viewer/​src/​cli.rs Adds RemoteApp options and rejects RPC combinations.
crates/​ironrdp-viewer/​src/​app.rs Routes RemoteApp output, window events, and input.
crates/​ironrdp-viewer/​Cargo.toml Adds the RAIL dependency and marks the public facade dependency.
crates/​ironrdp-testsuite-extra/​tests/​client/​viewer_rail.rs Tests RemoteApp models and rendering helpers.
crates/​ironrdp-testsuite-extra/​tests/​client/​mod.rs Registers the RemoteApp viewer tests.
Cargo.lock Records the viewer’s RAIL dependency.

Review effort: Balanced

Comment thread crates/ironrdp-viewer/src/rail.rs
Comment thread crates/ironrdp-viewer/src/rail.rs Outdated
Comment thread crates/ironrdp-viewer/src/app.rs Outdated
Comment thread crates/ironrdp-viewer/src/app.rs Outdated
Comment thread crates/ironrdp-viewer/src/rail.rs
Comment thread crates/ironrdp-viewer/src/rail.rs Outdated
Server window sizes reached native window creation and the painting
buffers unbounded, so a 32766x32766 window could request about 4 GiB.
Local window sizes are now bounded to the window pixel budget, and a
window the platform makes larger is not painted.

Recreating a window for a late or changed owner destroyed the native
windows it owned while their records stayed. The window and every
window it owns are now dropped owned-first and recreated owners-first,
owner changes on existing windows are applied the same way, and a
cyclic ownership gets no owner instead of recreating forever.

Activate and Close requests and the release of held input after a
focus loss were dropped when the session input queue was full; they
are now queued in order and retried. The hidden server pointer also
stays hidden in windows created later.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

This branch was previously deployed

1 inactive deployment
llm-providers — 17f97246 Deployed Oct 23, 2026 by mamoreau-devolutions via Classify pull request #7767
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ai-reviewed/3 Final automated review completed breaking-change Includes a breaking change, and requires special scrutiny at the boundaries kind/protocol Affects RDP or related protocol behavior risk/medium Behavioral change that does not substantially alter a core public API size/XXL Size: 1300 or more counted lines or 50 or more files

Development

Successfully merging this pull request may close these issues.

2 participants