Repository navigation
feat(viewer): run RemoteApp programs in native windows - #2201
Conversation
|
Line counts: production code about +300/−166 (new Not run against a server yet. |
415ac58 to
9b1ff99
Compare
20d6c21 to
4e639ff
Compare
There was a problem hiding this comment.
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; |
There was a problem hiding this comment.
[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.
There was a problem hiding this comment.
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.
9b1ff99 to
e0da823
Compare
4e639ff to
82d660a
Compare
e0da823 to
52a684c
Compare
82d660a to
8495bbf
Compare
52a684c to
528e98e
Compare
91ecac7 to
23cda84
Compare
c85d8ee to
8200b8d
Compare
23cda84 to
e5bce84
Compare
8200b8d to
990d7da
Compare
e5bce84 to
50a489e
Compare
990d7da to
184ab70
Compare
184ab70 to
56201ee
Compare
97efcc4 to
71af41a
Compare
56201ee to
b735e54
Compare
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>
b735e54 to
182bade
Compare
There was a problem hiding this comment.
🟡 Changes recommended
Unbounded rendering allocations, native ownership handling, and dropped input during queue saturation leave significant correctness and reliability issues.
6 open issues
Bound native window and crop allocations by pixel budget · New Preserve owned descendants during late-owner recreation · New Retry RAIL controls when the input queue is full · New Retry focus-loss releases when the input queue is full · New Apply owner changes to existing native windows · New Persist cursor visibility for windows created later · New
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
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>


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