Skip to content

feat: allow WGC capture path to attempt minimized UWP windows (remove IsIconic early-return)#1736

Open
mvanhorn wants to merge 2 commits into
trycua:mainfrom
mvanhorn:feat/1600-feat-windowsgraphicscapture-path-for-bac
Open

feat: allow WGC capture path to attempt minimized UWP windows (remove IsIconic early-return)#1736
mvanhorn wants to merge 2 commits into
trycua:mainfrom
mvanhorn:feat/1600-feat-windowsgraphicscapture-path-for-bac

Conversation

@mvanhorn
Copy link
Copy Markdown

@mvanhorn mvanhorn commented May 27, 2026

Summary

feat: Windows.Graphics.Capture path for background-collapsed UWP windows in cua-driver-rs

Closes #1600


AI was used for assistance.

Summary by CodeRabbit

  • Bug Fixes

    • Improved capture handling for minimized windows. The system now attempts to capture them through the standard pipeline with timeout handling instead of failing immediately.
  • Documentation

    • Updated capture documentation regarding minimized and cloaked window behavior and fallback mechanisms.
  • Tests

    • Added integration tests for UWP application screenshot capture scenarios.

Review Change Stack

@vercel
Copy link
Copy Markdown
Contributor

vercel Bot commented May 27, 2026

@mvanhorn is attempting to deploy a commit to the Cua Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 27, 2026

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 3e83a05f-ccfe-445e-a5b2-6c1b4cf38bfe

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

WGC module removes the early check that rejected minimized windows, allowing them to proceed through standard capture and frame polling with timeout handling. Documentation updated accordingly. New Windows-only integration tests validate UWP app screenshot capture for both normal and minimized window states.

Changes

WGC Minimized Window Capture Support

Layer / File(s) Summary
WGC capture behavior - remove minimized window guard
libs/cua-driver/rust/crates/platform-windows/src/wgc.rs
Documentation updated to state minimized/cloaked windows may fail to produce frames but WGC will attempt capture with structured timeout for fallback. Early-exit guard via IsIconic removed so minimized windows flow through standard WGC frame polling. IsIconic import removed as now-unused.
WGC minimized window capture tests
libs/cua-driver/rust/crates/platform-windows/tests/capture_uwp_test.rs
Windows-only integration test module with helper to launch UWP Calculator app and poll for window, PNG dimension validator, and two ignored tests: one capturing the calculator window normally, another minimizing via unsafe Windows API call, capturing via WGC, restoring, and validating PNG dimensions and pixel buffer size.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Poem

A tiny guard once blocked the way,
Minimized windows couldn't stay.
Now WGC tries with patient grace,
Timeout handles every case.
Tests ensure our Calculator gleams,
Even in collapsed window dreams. 🪟✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed The PR addresses the core requirement from #1600: implementing Windows.Graphics.Capture to handle background-collapsed UWP windows, demonstrated by the WGC module changes and test additions.
Out of Scope Changes check ✅ Passed All changes align with issue #1600's scope: WGC module updates for capturing background-collapsed windows and integration tests for the UWP capture path.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Title check ✅ Passed The title clearly and specifically describes the main change: removing the IsIconic early-return check to allow WGC to attempt capturing minimized UWP windows.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
libs/cua-driver/rust/crates/platform-windows/tests/capture_uwp_test.rs (1)

20-27: ⚡ Quick win

Use launched PID for window matching instead of title text.

At Line 20 and Line 26, the test ignores the PID returned from launch_uwp and matches by "calculator" title. That is locale-dependent and can accidentally pick a pre-existing Calculator window. Filtering by the launched PID will make this test much more deterministic.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@libs/cua-driver/rust/crates/platform-windows/tests/capture_uwp_test.rs`
around lines 20 - 27, The test currently ignores the PID returned from
launch_uwp::launch_uwp(CALCULATOR_AUMID, "") and searches windows by title;
change it to capture the returned _pid (e.g., let pid =
launch_uwp::launch_uwp(...)?;) and use that PID to find the window from
platform_windows::win32::windows::list_windows(None) by comparing the window's
process id field (e.g., window.process_id or window.pid) to the launched pid
instead of matching title text so the loop deterministically selects the
launched UWP process.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@libs/cua-driver/rust/crates/platform-windows/tests/capture_uwp_test.rs`:
- Around line 59-79: In minimized_calculator_wgc_attempts_composited_capture,
don't unwrap the wgc::screenshot_window_via_wgc result with result?; instead
match on result from wgc::screenshot_window_via_wgc(window.hwnd) and accept
either the successful tuple (pixels, w, h) which you then validate as before, or
the expected structured timeout error returned by the wgc module; implement the
match using either matches!(err, wgc::...::Timeout) or an
is_timeout()/is_timeout_variant() helper on the error type so the test passes
when WGC legitimately times out while still failing for other unexpected errors.

---

Nitpick comments:
In `@libs/cua-driver/rust/crates/platform-windows/tests/capture_uwp_test.rs`:
- Around line 20-27: The test currently ignores the PID returned from
launch_uwp::launch_uwp(CALCULATOR_AUMID, "") and searches windows by title;
change it to capture the returned _pid (e.g., let pid =
launch_uwp::launch_uwp(...)?;) and use that PID to find the window from
platform_windows::win32::windows::list_windows(None) by comparing the window's
process id field (e.g., window.process_id or window.pid) to the launched pid
instead of matching title text so the loop deterministically selects the
launched UWP process.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: e914f668-123a-46e4-a583-86a7a4ce5c70

📥 Commits

Reviewing files that changed from the base of the PR and between 7d893ce and a9e6249.

📒 Files selected for processing (2)
  • libs/cua-driver/rust/crates/platform-windows/src/wgc.rs
  • libs/cua-driver/rust/crates/platform-windows/tests/capture_uwp_test.rs

Comment on lines +59 to +79
fn minimized_calculator_wgc_attempts_composited_capture() -> Result<()> {
let window = launch_calculator_and_wait_for_window()?;
let hwnd = HWND(window.hwnd as *mut _);

unsafe {
let _ = ShowWindow(hwnd, SW_MINIMIZE);
}
sleep(Duration::from_millis(500));

let result = wgc::screenshot_window_via_wgc(window.hwnd);

unsafe {
let _ = ShowWindow(hwnd, SW_RESTORE);
}

let (pixels, w, h) = result?;
assert!(
w > 120 && h > 30,
"expected real Calculator UI dimensions from minimized WGC capture, got {w}x{h}"
);
assert_eq!(pixels.len(), w as usize * h as usize * 4);
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.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Minimized WGC test should accept structured timeout as a valid outcome.

At Line 74, result? makes this test fail on systems where minimized/cloaked windows legitimately produce no frame within timeout (which this PR explicitly documents as possible). The test should assert either: (a) successful composited capture with valid dimensions, or (b) the expected structured timeout error.

Proposed adjustment
-    let (pixels, w, h) = result?;
-    assert!(
-        w > 120 && h > 30,
-        "expected real Calculator UI dimensions from minimized WGC capture, got {w}x{h}"
-    );
-    assert_eq!(pixels.len(), w as usize * h as usize * 4);
+    match result {
+        Ok((pixels, w, h)) => {
+            assert!(
+                w > 120 && h > 30,
+                "expected real Calculator UI dimensions from minimized WGC capture, got {w}x{h}"
+            );
+            assert_eq!(pixels.len(), w as usize * h as usize * 4);
+        }
+        Err(e) => {
+            let msg = e.to_string();
+            assert!(
+                msg.contains("no frame within 1500 ms"),
+                "unexpected minimized WGC failure: {e:#}"
+            );
+        }
+    }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
fn minimized_calculator_wgc_attempts_composited_capture() -> Result<()> {
let window = launch_calculator_and_wait_for_window()?;
let hwnd = HWND(window.hwnd as *mut _);
unsafe {
let _ = ShowWindow(hwnd, SW_MINIMIZE);
}
sleep(Duration::from_millis(500));
let result = wgc::screenshot_window_via_wgc(window.hwnd);
unsafe {
let _ = ShowWindow(hwnd, SW_RESTORE);
}
let (pixels, w, h) = result?;
assert!(
w > 120 && h > 30,
"expected real Calculator UI dimensions from minimized WGC capture, got {w}x{h}"
);
assert_eq!(pixels.len(), w as usize * h as usize * 4);
fn minimized_calculator_wgc_attempts_composited_capture() -> Result<()> {
let window = launch_calculator_and_wait_for_window()?;
let hwnd = HWND(window.hwnd as *mut _);
unsafe {
let _ = ShowWindow(hwnd, SW_MINIMIZE);
}
sleep(Duration::from_millis(500));
let result = wgc::screenshot_window_via_wgc(window.hwnd);
unsafe {
let _ = ShowWindow(hwnd, SW_RESTORE);
}
match result {
Ok((pixels, w, h)) => {
assert!(
w > 120 && h > 30,
"expected real Calculator UI dimensions from minimized WGC capture, got {w}x{h}"
);
assert_eq!(pixels.len(), w as usize * h as usize * 4);
}
Err(e) => {
let msg = e.to_string();
assert!(
msg.contains("no frame within 1500 ms"),
"unexpected minimized WGC failure: {e:#}"
);
}
}
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@libs/cua-driver/rust/crates/platform-windows/tests/capture_uwp_test.rs`
around lines 59 - 79, In minimized_calculator_wgc_attempts_composited_capture,
don't unwrap the wgc::screenshot_window_via_wgc result with result?; instead
match on result from wgc::screenshot_window_via_wgc(window.hwnd) and accept
either the successful tuple (pixels, w, h) which you then validate as before, or
the expected structured timeout error returned by the wgc module; implement the
match using either matches!(err, wgc::...::Timeout) or an
is_timeout()/is_timeout_variant() helper on the error type so the test passes
when WGC legitimately times out while still failing for other unexpected errors.

@mvanhorn mvanhorn changed the title feat: Windows.Graphics.Capture path for background-collapsed UWP windows in cua-driver-rs feat: allow WGC capture path to attempt minimized UWP windows (remove IsIconic early-return) May 27, 2026
Removing the ignored integration test that referenced symbols
(win32::windows::WindowInfo, capture::png_dimensions_pub) which don't
exist on this branch. It would not have compiled if not for the
#[ignore]. The IsIconic guard removal can stand on its own; once the
actual WGC path lands we can add a test that compiles.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

cua-driver-rs (Windows): screenshot of background-collapsed UWP windows (Calculator) returns wrong-size capture — WGC needed

1 participant