Skip to content

v3(windows): add WindowsOptions.UseVisualHosting to fix WebView2 hangs over RDP#5380

Open
MerIijn wants to merge 1 commit into
wailsapp:masterfrom
MerIijn:fix/webview2-rdp-visual-hosting
Open

v3(windows): add WindowsOptions.UseVisualHosting to fix WebView2 hangs over RDP#5380
MerIijn wants to merge 1 commit into
wailsapp:masterfrom
MerIijn:fix/webview2-rdp-visual-hosting

Conversation

@MerIijn
Copy link
Copy Markdown

@MerIijn MerIijn commented May 9, 2026

Problem

When a Wails3 app is used over Microsoft Remote Desktop's iOS client (or any RDP client that provisions a virtual monitor with a different DPI context mid-session), WebView2's default windowed hosting forces a synchronous DComp re-marshal on every controller call. Each PutIsVisible, MoveFocus, first-paint, and surface release blocks the UI thread for ~2 s, and the bad state persists across reconnects until the host is rebooted. On a typical popup-heavy app this is 4-8 s per popup open and 2-3 s of parent-window stall on close.

A native Win32 + WebView2 sample on the same machine is unaffected, which is consistent with this being a hosting-mode interaction rather than a generic WebView2 or DWM bug.

Fix

Microsoft documents COREWEBVIEW2_FORCED_HOSTING_MODE_WINDOW_TO_VISUAL as the workaround for "monitor-scale changes can cause hangs." With visual hosting the controller's compositor surface is owned through a DComp visual the host owns, so DPI-context changes don't trigger the synchronous re-marshal.

This PR adds an opt-in WindowsOptions.UseVisualHosting field. When set, newPlatformApp sets the COREWEBVIEW2_FORCED_HOSTING_MODE env var before any WebView2 environment is initialised.

Default is false to preserve existing behavior - windowed hosting remains the default and no apps see a behavior change unless they opt in.

Usage

app := application.New(application.Options{
    Windows: application.WindowsOptions{
        UseVisualHosting: true,
    },
})

Verification

Confirmed in the iPhone-RDP-poisoned graphics state on Windows Server 2025 that:

  • Before: every popup window 4-8 s click->content; close blocks parent UI ~2 s.
  • After: popups open within Chromium's normal navigation time (~150-500 ms); close does not block the parent window.

The fix is identical to what the Microsoft Win32_GettingStarted sample relies on implicitly, which is why that sample isn't affected by the same RDP graphics state.

References

Tested on

  • Windows Server 2025 Datacenter Evaluation (build 26100)
  • Wails v3 master (commit af4669e, v3.0.0-alpha.88)
  • WebView2 runtime 148.0.3967.54

Summary by CodeRabbit

  • New Features
    • Added Windows configuration option to force WebView2 to use Visual hosting mode, providing an alternative rendering approach for users who require it.

Review Change Stack

…s over RDP

When a Wails3 app is used over Microsoft Remote Desktop's iOS client (or
any RDP client that provisions a virtual monitor with a different DPI
context mid-session), WebView2's default windowed hosting forces a
synchronous DComp re-marshal on every controller call. Each PutIsVisible,
MoveFocus, first-paint, and surface release blocks the UI thread for
~2 s, and the bad state persists across reconnects until the host is
rebooted. The aggregated cost on a typical popup-heavy app is 4-8 s for
open and 2-3 s of parent-window stalls on close.

A native Win32 + WebView2 sample on the same machine is unaffected,
which is consistent with this being a hosting-mode interaction rather
than a generic WebView2 or DWM bug.

The Microsoft-documented fix is to set the
COREWEBVIEW2_FORCED_HOSTING_MODE env var to
COREWEBVIEW2_HOSTING_MODE_WINDOW_TO_VISUAL before WebView2 initialises.
With visual hosting the controller's compositor surface is owned through
a DComp visual the host owns, so DPI-context changes don't trigger the
synchronous re-marshal.

This change adds a WindowsOptions.UseVisualHosting opt-in (default false
to preserve existing behavior) that sets the env var inside
newPlatformApp, before any WebView2 environment is constructed.

Refs:
- https://learn.microsoft.com/en-us/microsoft-edge/webview2/concepts/windowed-vs-visual-hosting
- MicrosoftEdge/WebView2Feedback#5248
- MicrosoftEdge/WebView2Feedback#4485
- MicrosoftEdge/WebView2Feedback#1212

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 9, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 61ee6d5f-27d1-46e7-b240-72826700f1cc

📥 Commits

Reviewing files that changed from the base of the PR and between af4669e and 628f184.

📒 Files selected for processing (2)
  • v3/pkg/application/application_options.go
  • v3/pkg/application/application_windows.go

Walkthrough

This PR introduces a Windows-specific configuration option that allows applications to control WebView2's hosting mode. A new UseVisualHosting boolean field is added to WindowsOptions, and during platform app initialization, when enabled, it sets an environment variable to force WebView2 to use IDCompositionVisual hosting mode.

Changes

Windows WebView2 Visual Hosting Configuration

Layer / File(s) Summary
Configuration Option
v3/pkg/application/application_options.go
WindowsOptions struct gains the exported UseVisualHosting boolean field with documentation describing its effect on WebView2 hosting mode.
Environment Setup
v3/pkg/application/application_windows.go
newPlatformApp conditionally sets the COREWEBVIEW2_FORCED_HOSTING_MODE environment variable when UseVisualHosting is enabled, before WebView2 initialization.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~8 minutes

Suggested labels

Enhancement, Windows, v3, size:M

Suggested reviewers

  • leaanthony

Poem

🐰 A visual host now takes the stage,
WebView2 composing without rage,
One flag to rule the rendering way,
IDComposition saves the day! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main change: adding UseVisualHosting to WindowsOptions to fix WebView2 RDP hangs, directly matching the changeset.
Description check ✅ Passed The description comprehensively covers the problem, solution, usage example, verification, and references, but the PR checklist items are not marked and testing configuration details are missing.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

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

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 golangci-lint (2.12.1)

level=error msg="[linters_context] typechecking error: pattern ./...: directory prefix . does not contain main module or its selected dependencies"

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


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.

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.

2 participants