Skip to content

feat: Add Content Protection for Windows and macOS#4485

Merged
leaanthony merged 7 commits into
v3-alphafrom
v3-alpha-feature/content-protection
Aug 9, 2025
Merged

feat: Add Content Protection for Windows and macOS#4485
leaanthony merged 7 commits into
v3-alphafrom
v3-alpha-feature/content-protection

Conversation

@leaanthony

@leaanthony leaanthony commented Aug 8, 2025

Copy link
Copy Markdown
Member

Summary

Adds content protection capability to prevent window contents from being captured by screen recording/sharing software.

Usage

// Enable at window creation
window := app.Window.NewWithOptions(application.WebviewWindowOptions{
    ContentProtectionEnabled: true,
})

// Or toggle at runtime
window.SetContentProtection(true)

Platform Support

  • Windows: Uses WDA_EXCLUDEFROMCAPTURE (Windows 10 2004+), falls back to WDA_MONITOR
  • macOS: Uses NSWindowSharingType for screen sharing protection
  • Linux: No-op (not implemented)

Based on original v2 work by @Taiterbase in #4241

Summary by CodeRabbit

  • New Features
    • Introduced content protection for windows on Windows and macOS platforms, preventing screen capture and recording.
    • Added a new method to enable or disable content protection for application windows.
    • Updated example application with a menu item to create windows with content protection enabled (non-Linux platforms).
  • Documentation
    • Expanded window management documentation with a detailed section on content protection, usage examples, supported platforms, and limitations.
    • Updated changelogs to reflect the addition of content protection support.
    • Corrected phrasing and formatting in changelog entries for improved clarity.
  • Chores
    • Extended cleanup patterns to include Linux package artifact files for removal.

- Prevents window contents from being captured by screen recording/sharing software
- Windows: Uses WDA_EXCLUDEFROMCAPTURE on Windows 10 2004+, falls back to WDA_MONITOR
- macOS: Uses NSWindowSharingType to set window as read-only for screen sharing
- Added ContentProtectionEnabled option to WebviewWindowOptions
- Added SetContentProtection() method for runtime control
- Added comprehensive documentation and example usage
@coderabbitai

coderabbitai Bot commented Aug 8, 2025

Copy link
Copy Markdown
Contributor

Caution

Review failed

The pull request is closed.

Walkthrough

This change introduces a cross-platform "Content Protection" feature for application windows, primarily targeting Windows and macOS. New methods and fields are added to window interfaces and implementations to enable or disable content protection, preventing screen capture and recording. Documentation and usage examples are updated, and platform-specific logic is implemented for Windows and macOS, with Linux stubbing the feature.

Changes

Cohort / File(s) Change Summary
Documentation updates
docs/src/content/docs/learn/windows.mdx, docs/src/content/docs/changelog.mdx, v3/UNRELEASED_CHANGELOG.md
Added documentation for content protection, usage examples, platform notes, and changelog entries. Minor changelog phrasing fix.
Example usage
v3/examples/window/main.go
Added a new menu item to demonstrate creation of a content-protected window (non-Linux only).
Window interface and options
v3/pkg/application/window.go, v3/pkg/application/webview_window_options.go
Added SetContentProtection method to the Window interface and a ContentProtectionEnabled field to window options.
Core content protection implementation
v3/pkg/application/webview_window.go
Added SetContentProtection to WebviewWindow and its implementation interface.
Platform: macOS
v3/pkg/application/webview_window_darwin.go
Implemented content protection logic using NSWindowSharingType for macOS windows.
Platform: Linux
v3/pkg/application/webview_window_linux.go
Added stub method for content protection (no-op on Linux).
Platform: Windows - API integration
v3/pkg/w32/user32.go, v3/pkg/w32/wda.go
Added Windows API bindings and logic for SetWindowDisplayAffinity and affinity flags.
Platform: Windows - Window logic
v3/pkg/application/webview_window_windows.go
Integrated content protection logic into window creation and runtime on Windows.
Cleanup patterns
v3/tasks/cleanup/cleanup.go
Added new file patterns for Linux package artifacts cleanup.

Sequence Diagram(s)

sequenceDiagram
    participant App
    participant Window (cross-platform)
    participant PlatformAPI (Win/Mac)
    App->>Window: SetContentProtection(true/false)
    alt impl not initialized
        Window->>Window: Set option ContentProtectionEnabled
    else impl initialized
        Window->>PlatformAPI: setContentProtection(true/false)
        alt Windows
            PlatformAPI->>PlatformAPI: SetWindowDisplayAffinity(hwnd, flag)
        else macOS
            PlatformAPI->>PlatformAPI: Set NSWindow sharingType
        else Linux
            PlatformAPI->>PlatformAPI: (no-op)
        end
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related issues

Possibly related PRs

Suggested labels

lgtm

Poem

A window with secrets, now safe from the screen,
Protected from capture—no snooping is seen!
Mac and Windows both heed the call,
While Linux just shrugs, doing nothing at all.
With menus and docs all tidy and neat,
This bunny hops on—content discreet! 🐇✨

Note

🔌 MCP (Model Context Protocol) integration is now available in Early Access!

Pro users can now connect to remote MCP servers under the Integrations page to get reviews and chat conversations that understand additional development context.


📜 Recent review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b9f3c83 and 39bd860.

📒 Files selected for processing (1)
  • v3/pkg/application/webview_window_darwin.go (3 hunks)
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch v3-alpha-feature/content-protection

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@dosubot dosubot Bot added the size:L This PR changes 100-499 lines, ignoring generated files. label Aug 8, 2025
@github-actions github-actions Bot added Documentation Improvements or additions to documentation Windows MacOS Linux v3-alpha labels Aug 8, 2025
@dosubot dosubot Bot added Enhancement New feature or request go Pull requests that update Go code labels Aug 8, 2025
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Aug 8, 2025

Copy link
Copy Markdown

Deploying wails with  Cloudflare Pages  Cloudflare Pages

Latest commit: b9f3c83
Status: ✅  Deploy successful!
Preview URL: https://c6c8f6f9.wails.pages.dev
Branch Preview URL: https://v3-alpha-feature-content-pro.wails.pages.dev

View logs

@coderabbitai coderabbitai 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.

Actionable comments posted: 7

🧹 Nitpick comments (6)
v3/pkg/application/webview_window_options.go (1)

138-141: Clarify platform scope and default in the new option’s doc comment

Match the style used for IgnoreMouseEvents (Windows + Mac only) and note Linux no-op/default.

-	// ContentProtectionEnabled specifies whether content protection is enabled, preventing screen capture and recording.
+	// ContentProtectionEnabled specifies whether content protection is enabled, preventing screen capture/recording.
+	// Windows + Mac only (no-op on Linux). Default: false.
 	ContentProtectionEnabled bool
v3/UNRELEASED_CHANGELOG.md (1)

20-21: Wording/consistency: “Windows and macOS”; optionally note Linux no-op

Use “macOS” (consistent across docs) and mention the Linux no-op to set expectations.

-- Add Content Protection on Windows/Mac by [@leaanthony](https://github.com/leaanthony) based on the original work of [@Taiterbase](https://github.com/Taiterbase) in this [PR](https://github.com/wailsapp/wails/pull/4241)
+- Add Content Protection on Windows and macOS (Linux no-op) by [@leaanthony](https://github.com/leaanthony), based on the original work of [@Taiterbase](https://github.com/Taiterbase) in this [PR](https://github.com/wailsapp/wails/pull/4241)
v3/pkg/application/webview_window_linux.go (1)

427-432: Annotate Linux content protection as an explicit no-op for clarity

Set content protection is intentionally unsupported on Linux. Matching the nearby snapAssist comment improves readability and avoids confusion.

-func (w *linuxWebviewWindow) setContentProtection(enabled bool) {}
+func (w *linuxWebviewWindow) setContentProtection(enabled bool) {} // No-op on Linux
v3/examples/window/main.go (1)

124-135: Good example; minor clarity/consistency tweaks suggested

Nice addition demonstrating enabling content protection at creation. Two optional improvements:

  • Clarify the label so users know it’s supported on Windows/macOS:
- myMenu.Add("New WebviewWindow (Content Protection Enabled)").
+ myMenu.Add("New WebviewWindow (Content Protection, Windows/macOS)").
  • Optional: For consistency with other OS-guarded examples below, explicitly guard for Windows/macOS instead of “not Linux.” This avoids surprising behavior on any other unsupported GOOS:
// replace: if runtime.GOOS != "linux" {
if runtime.GOOS == "windows" || runtime.GOOS == "darwin" {
  • Optional: The PR mentions runtime toggling; consider adding a toggle example for the current window:
// Example addition near other Controls/State items
if runtime.GOOS == "windows" || runtime.GOOS == "darwin" {
  stateMenu.Add("Toggle Content Protection").OnClick(func(ctx *application.Context) {
    currentWindow(func(w *application.WebviewWindow) {
      // If you expose a getter, prefer it. Otherwise, track a local state or flip a stored flag.
      // Example assumes you track a boolean somewhere:
      // contentProtected = !contentProtected
      // w.SetContentProtection(contentProtected)
      w.SetContentProtection(true) // or false to disable
    })
  })
}
v3/pkg/w32/wda.go (1)

5-9: Constants look correct; consider adding short doc comments

WDA_NONE=0x0, WDA_MONITOR=0x1, WDA_EXCLUDEFROMCAPTURE=0x11 are correct. Adding brief comments on semantics aids maintainability (e.g., EXCLUDEFROMCAPTURE: Windows 10 2004+, blocks OS capture APIs; MONITOR: restricts display to a monitor, partial capture protection).

docs/src/content/docs/learn/windows.mdx (1)

199-201: Cross-reference the new API

Consider linking this method item to the Content Protection section below for discoverability, e.g., “See Content Protection for platform specifics.”

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1a03404 and b3d5a94.

📒 Files selected for processing (12)
  • docs/src/content/docs/changelog.mdx (1 hunks)
  • docs/src/content/docs/learn/windows.mdx (1 hunks)
  • v3/UNRELEASED_CHANGELOG.md (1 hunks)
  • v3/examples/window/main.go (1 hunks)
  • v3/pkg/application/webview_window.go (2 hunks)
  • v3/pkg/application/webview_window_darwin.go (2 hunks)
  • v3/pkg/application/webview_window_linux.go (1 hunks)
  • v3/pkg/application/webview_window_options.go (1 hunks)
  • v3/pkg/application/webview_window_windows.go (2 hunks)
  • v3/pkg/application/window.go (1 hunks)
  • v3/pkg/w32/user32.go (1 hunks)
  • v3/pkg/w32/wda.go (1 hunks)
🧰 Additional context used
🧠 Learnings (10)
📚 Learning: 2024-09-20T23:34:29.841Z
Learnt from: nixpare
PR: wailsapp/wails#3763
File: v3/examples/keybindings/main.go:16-17
Timestamp: 2024-09-20T23:34:29.841Z
Learning: In the codebase, `application.Options.KeyBindings` uses the `application.Window` type, whereas `application.WebviewWindowOptions.KeyBindings` uses `*application.WebviewWindow`. This is intentional and acceptable.

Applied to files:

  • v3/pkg/application/webview_window_options.go
  • v3/pkg/application/webview_window.go
  • v3/pkg/application/webview_window_linux.go
  • v3/pkg/application/webview_window_darwin.go
  • docs/src/content/docs/learn/windows.mdx
  • v3/examples/window/main.go
  • v3/pkg/application/webview_window_windows.go
📚 Learning: 2025-04-29T23:54:07.488Z
Learnt from: popaprozac
PR: wailsapp/wails#4256
File: v2/internal/frontend/desktop/linux/notifications.go:27-28
Timestamp: 2025-04-29T23:54:07.488Z
Learning: In Wails v2, unlike v3-alpha which has a `ServiceShutdown` method for services, there is no standardized teardown pattern for frontend implementations. When implementing features that require cleanup (like goroutines or resources), add explicit cleanup methods (e.g., `CleanupNotifications()`) that handle resource release, context cancellation, and connection closure.

Applied to files:

  • docs/src/content/docs/changelog.mdx
📚 Learning: 2025-08-08T13:15:20.287Z
Learnt from: APshenkin
PR: wailsapp/wails#4484
File: v2/internal/frontend/utils/urlValidator.go:25-31
Timestamp: 2025-08-08T13:15:20.287Z
Learning: In Wails v2 (PR wailsapp/wails#4484), for BrowserOpenURL URL validation (v2/internal/frontend/utils/urlValidator.go), maintainers (APshenkin) prefer not to restrict schemes to an http/https allowlist because supported schemes may vary. The allowlist suggestion is declined; continue with the existing denylist approach and generic validation.

Applied to files:

  • docs/src/content/docs/changelog.mdx
📚 Learning: 2024-10-08T22:11:37.054Z
Learnt from: nixpare
PR: wailsapp/wails#3763
File: v3/pkg/application/application_options.go:93-93
Timestamp: 2024-10-08T22:11:37.054Z
Learning: The `KeyBindings` property of `application.Option` uses the `application.Window` type, while `application.WebviewWindowOptions` still accepts `*application.WebviewWindow`, and this is intentional.

Applied to files:

  • v3/pkg/application/webview_window.go
  • docs/src/content/docs/learn/windows.mdx
📚 Learning: 2025-08-08T09:13:16.884Z
Learnt from: APshenkin
PR: wailsapp/wails#4480
File: v2/internal/frontend/desktop/darwin/message.h:17-19
Timestamp: 2025-08-08T09:13:16.884Z
Learning: In Wails v2 bindings origin verification, processBindingMessage intentionally has different signatures across platforms: Darwin includes an isMainFrame bool (WKWebKit provides it), Linux uses two params (message, source) as WebKitGTK doesn’t expose main-frame info there, and Windows handles origin checks in Go via WebView2 sender/args without a C bridge. This divergence is acceptable/expected per maintainer (APshenkin).

Applied to files:

  • v3/pkg/application/webview_window.go
  • v3/pkg/w32/user32.go
  • v3/pkg/application/webview_window_darwin.go
  • v3/examples/window/main.go
📚 Learning: 2024-09-21T13:34:24.145Z
Learnt from: nixpare
PR: wailsapp/wails#3763
File: v3/pkg/application/webview_window_bindings_darwin.h:0-0
Timestamp: 2024-09-21T13:34:24.145Z
Learning: In this codebase, typedefs for window references (like replacing `void *` with `WindowRef`) are not preferred; using `void *` is acceptable.

Applied to files:

  • v3/pkg/w32/user32.go
📚 Learning: 2024-09-21T09:56:48.126Z
Learnt from: nixpare
PR: wailsapp/wails#3763
File: v3/pkg/application/webview_panel_darwin.go:88-89
Timestamp: 2024-09-21T09:56:48.126Z
Learning: Safety checks for `p.nsPanel` are performed in the `SetFloating` method of `WebviewPanel`, following the `WebviewWindow` and `macosWebviewWindow` implementations and code style.

Applied to files:

  • v3/pkg/application/webview_window_darwin.go
📚 Learning: 2024-10-08T22:11:37.054Z
Learnt from: leaanthony
PR: wailsapp/wails#3763
File: v3/examples/window/main.go:472-475
Timestamp: 2024-10-08T22:11:37.054Z
Learning: In `v3/examples/window/main.go`, `time.Sleep` is used within a goroutine and does not block the UI thread.

Applied to files:

  • v3/pkg/w32/wda.go
  • docs/src/content/docs/learn/windows.mdx
  • v3/examples/window/main.go
📚 Learning: 2025-01-24T22:41:18.566Z
Learnt from: leaanthony
PR: wailsapp/wails#4031
File: v3/pkg/application/menu.go:199-202
Timestamp: 2025-01-24T22:41:18.566Z
Learning: In the Wails menu system (v3/pkg/application/menu.go), shared state between menus is intentionally designed and desirable. Methods like `Append()` and `Prepend()` should maintain shared references to menu items rather than creating deep copies.

Applied to files:

  • v3/examples/window/main.go
📚 Learning: 2024-09-30T06:14:32.602Z
Learnt from: leaanthony
PR: wailsapp/wails#3763
File: v3/internal/commands/appimage_testfiles/main.go:295-299
Timestamp: 2024-09-30T06:14:32.602Z
Learning: In `v3/internal/commands/appimage_testfiles/main.go`, `time.Sleep` is used within a goroutine and does not block the UI thread.

Applied to files:

  • v3/examples/window/main.go
🧬 Code Graph Analysis (3)
v3/pkg/application/webview_window.go (1)
v3/pkg/application/window.go (1)
  • Window (14-92)
v3/pkg/w32/wda.go (1)
v3/pkg/w32/consts.go (1)
  • IsWindowsVersionAtLeast (33-37)
v3/pkg/application/webview_window_windows.go (1)
v3/pkg/w32/wda.go (3)
  • WDA_EXCLUDEFROMCAPTURE (8-8)
  • WDA_NONE (6-6)
  • SetWindowDisplayAffinity (11-21)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Run Go Tests v3 (ubuntu-latest, 1.24)
  • GitHub Check: Run Go Tests v3 (windows-latest, 1.24)
🔇 Additional comments (4)
v3/pkg/application/window.go (1)

91-92: Confirm external Window implementations updated

I’ve verified that the only internal Window implementation (WebviewWindow in v3/pkg/application/webview_window.go:524) already implements SetContentProtection, so no internal changes are missing. However, adding SetContentProtection(bool) Window to the exported Window interface is a breaking change.

• Internal implementations checked:
– WebviewWindow (v3/pkg/application/webview_window.go:524)

Next steps:
• Please review any external mocks or custom Window implementations (in downstream projects or tests) and update them to include SetContentProtection.

docs/src/content/docs/changelog.mdx (1)

184-184: Fix duplicate PR link and clarify attribution for Gin support

This line links the same PR twice and reads ambiguously (“original work … in this PR”). If there’s a separate original PR by @AnalogJ, please link that; otherwise, simplify the sentence to avoid duplication.

Proposed minimal edit:

- Gin support by [Lea Anthony](https://github.com/leaanthony) in [PR](https://github.com/wailsapp/wails/pull/3537) based on the original work of [@AnalogJ](https://github.com/AnalogJ) in this [PR](https://github.com/wailsapp/wails/pull/3537)
+ Gin support by [Lea Anthony](https://github.com/leaanthony) in [PR #3537](https://github.com/wailsapp/wails/pull/3537), based on original work by [@AnalogJ](https://github.com/AnalogJ).

If a different PR by @AnalogJ should be credited, replace the trailing text with the correct link instead of removing it.

Likely an incorrect or invalid review comment.

v3/pkg/application/webview_window.go (1)

115-116: Interface extension looks consistent.

Adding setContentProtection(enabled bool) to webviewWindowImpl aligns with the new Window API and platform implementations.

v3/pkg/application/webview_window_windows.go (1)

383-385: Verify UI-Thread Dispatch for SetContentProtection
I wasn’t able to find any UI/main-thread marshalling when
WebviewWindow.SetContentProtection calls into
windowsWebviewWindow.setContentProtection. Win32 APIs like
SetWindowDisplayAffinity must be invoked on the window’s UI thread.

Please confirm that toggling content protection runs on the OS-thread locked for your message loop. If it doesn’t, wrap the call in your application’s UI dispatch mechanism (e.g. via app.dispatch or similar).

• Wrapper in v3/pkg/application/webview_window.go (lines 524–528)
• Windows impl in v3/pkg/application/webview_window_windows.go (lines 2449–2454)

Comment thread docs/src/content/docs/learn/windows.mdx
Comment thread v3/pkg/application/webview_window_darwin.go
Comment on lines +1437 to +1439
func (w *macosWebviewWindow) setContentProtection(enabled bool) {
C.setContentProtection(w.nsWindow, C.bool(enabled))
}

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.

💡 Verification agent

🧩 Analysis chain

Main-thread requirement: this call must be invoked via InvokeSync.

macOS UI mutations must happen on the main thread. Given the current WebviewWindow.SetContentProtection implementation does not use InvokeSync, this will run off the main thread and can cause undefined behavior.

Recommendation: wrap the call site (in WebviewWindow.SetContentProtection) with InvokeSync. See suggested diff in webview_window.go comment.


🏁 Script executed:

#!/bin/bash
# Search for SetContentProtection in the repository
rg --color=never -n "SetContentProtection" .

# Also search for lower-case setContentProtection invocations
rg --color=never -n "setContentProtection" .

Length of output: 1422


#!/bin/bash
# Display WebviewWindow.SetContentProtection implementation
sed -n '520,560p' v3/pkg/application/webview_window.go

# Display top-level Window.SetContentProtection implementation
sed -n '80,120p' v3/pkg/application/window.go

# Search for any InvokeSync calls in the repo
rg --color=never -n "InvokeSync" .

🏁 Script executed:

#!/bin/bash
# Inspect the Objective-C implementation of setContentProtection in Darwin binding
sed -n '800,860p' v3/pkg/application/webview_window_darwin.go

Length of output: 1633


🏁 Script executed:

#!/bin/bash
# Extract WebviewWindow.SetContentProtection implementation
sed -n '510,560p' v3/pkg/application/webview_window.go

# Search for threading helpers in webview_window.go
rg --color=never -n "InvokeSync" v3/pkg/application/webview_window.go || true
rg --color=never -n "MainThread" v3/pkg/application/webview_window.go || true
rg --color=never -n "runtime\." v3/pkg/application/webview_window.go | head -n20

Length of output: 4211


Invoke setContentProtection on the main thread via InvokeSync

The current WebviewWindow.SetContentProtection calls w.impl.setContentProtection(b) directly. UI mutations on macOS must happen on the main thread, so this needs to be wrapped in InvokeSync, consistent with all other window operations.

• File: v3/pkg/application/webview_window.go, around line 524
• Change:

 func (w *WebviewWindow) SetContentProtection(b bool) Window {
     if w.impl == nil {
         w.options.ContentProtectionEnabled = b
     } else {
-        w.impl.setContentProtection(b)
+        InvokeSync(func() {
+            w.impl.setContentProtection(b)
+        })
     }
     return w
 }

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In v3/pkg/application/webview_window.go around line 524, the call to
w.impl.setContentProtection(b) must be wrapped inside an InvokeSync call to
ensure it runs on the main thread, as UI updates on macOS require main thread
execution. Modify the method to invoke setContentProtection using InvokeSync to
maintain thread safety and consistency with other window operations.

Comment thread v3/pkg/application/webview_window_windows.go
Comment thread v3/pkg/application/webview_window.go
Comment thread v3/pkg/w32/user32.go
Comment thread v3/pkg/w32/wda.go

@coderabbitai coderabbitai 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.

Actionable comments posted: 7

🔭 Outside diff range comments (1)
v3/pkg/application/webview_window_linux.go (1)

427-432: Add Linux wiring for content protection and debug logging

The Linux stub for setContentProtection is never invoked on window creation. To align with Windows and macOS, you should:

  • In v3/pkg/application/webview_window_linux.go, inside the func (w *linuxWebviewWindow) show() implementation (around where you register capabilities), add:
      // Process ContentProtection (Linux does not support it)
      w.setContentProtection(w.parent.options.ContentProtectionEnabled)
  • Update the stub at the bottom of that file to emit a debug log when enabled is true:
    func (w *linuxWebviewWindow) setContentProtection(enabled bool) {
    -   // no-op on Linux
    +   if enabled {
    +       globalApplication.debug("ContentProtectionEnabled requested on Linux: no-op (not supported)")
    +   }
    }

This ensures diagnostics are visible whenever an app requests content protection on Linux.

🧹 Nitpick comments (7)
docs/src/content/docs/changelog.mdx (1)

184-184: Duplicate/ambiguous PR reference; tighten wording

The line links to the same PR twice (“in PR … based on … in this PR”), which reads oddly. Suggest simplifying and making the platform naming consistent.

-- Gin support by [Lea Anthony](https://github.com/leaanthony) in [PR](https://github.com/wailsapp/wails/pull/3537) based on the original work of [@AnalogJ](https://github.com/AnalogJ) in this [PR](https://github.com/wailsapp/wails/pull/3537)
+- Gin support by [Lea Anthony](https://github.com/leaanthony), based on the original work of [@AnalogJ](https://github.com/AnalogJ) in [PR #3537](https://github.com/wailsapp/wails/pull/3537)
v3/UNRELEASED_CHANGELOG.md (1)

20-20: Changelog phrasing and platform naming consistency

Prefer “Windows and macOS” over “Windows/Mac”, and avoid “this PR” ambiguity in changelogs; use an explicit PR number.

-- Add Content Protection on Windows/Mac by [@leaanthony](https://github.com/leaanthony) based on the original work of [@Taiterbase](https://github.com/Taiterbase) in this [PR](https://github.com/wailsapp/wails/pull/4241)
+- Add Content Protection on Windows and macOS by [@leaanthony](https://github.com/leaanthony), based on the original work of [@Taiterbase](https://github.com/Taiterbase) in [PR #4241](https://github.com/wailsapp/wails/pull/4241)
v3/examples/window/main.go (1)

124-135: Demo improvement: showcase runtime toggling as well

Nice addition for initial enable. To fully demonstrate the feature per PR (toggle at runtime), consider adding two menu items under “State” or “Controls” that call SetContentProtection(true/false) on the current window. Example:

stateMenu.Add("Enable Content Protection").OnClick(func(ctx *application.Context) {
  currentWindow(func(w *application.WebviewWindow) { w.SetContentProtection(true) })
})
stateMenu.Add("Disable Content Protection").OnClick(func(ctx *application.Context) {
  currentWindow(func(w *application.WebviewWindow) { w.SetContentProtection(false) })
})
v3/pkg/w32/wda.go (1)

5-9: Nit: Add doc comments and link to MSDN

Add brief comments for the WDA_* flags and reference SetWindowDisplayAffinity docs. Improves readability and future maintenance.

 const (
-  WDA_NONE               = 0x00000000
-  WDA_MONITOR            = 0x00000001
-  WDA_EXCLUDEFROMCAPTURE = 0x00000011 // windows 10 2004+
+  // WDA_NONE disables display affinity restrictions.
+  WDA_NONE               = 0x00000000
+  // WDA_MONITOR restricts content to a local monitor (older fallback; will appear black in remote sessions).
+  WDA_MONITOR            = 0x00000001
+  // WDA_EXCLUDEFROMCAPTURE excludes the window from screen capture (Windows 10, version 2004+).
+  // See: https://learn.microsoft.com/windows/win32/api/winuser/nf-winuser-setwindowdisplayaffinity
+  WDA_EXCLUDEFROMCAPTURE = 0x00000011
 )
docs/src/content/docs/learn/windows.mdx (3)

199-201: Clarify cross-platform behavior in method list (optional)

Consider appending “(Windows/macOS; no-op on Linux)” to the bullet so readers scanning this list don’t miss the later platform support section.


208-238: Add caveats about thumbnails and remote sessions (Windows)

Two practical caveats worth calling out here:

  • With content protection enabled, Windows may show black thumbnails in Taskbar previews, Task View, and Snap Assist.
  • On Windows versions where the fallback (WDA_MONITOR) is used, the window will appear black in remote sessions (RDP/VM streaming/screen-share).

You can fold these into the “Platform Support” bullets or move them to Important Notes.


239-254: Expand Important Notes with Windows-specific behavior

To set expectations, add these items:

  • On Windows, taskbar thumbnails, Task View and Snap Assist previews may be black while protection is enabled.
  • On pre-2004 Windows (fallback to WDA_MONITOR), the window will be black in remote sessions (RDP/VMs) and many screen-sharing tools. This is expected.

Apply this diff inside the Important Notes list:

 1. Content protection does not prevent physical photography of the screen
 2. On Windows, the fallback for older versions provides partial protection
 3. Some screen capture tools may still be able to capture protected content using low-level APIs
 4. This feature should be part of a comprehensive security strategy, not the only protection
+5. Windows taskbar thumbnails, Task View and Snap Assist previews may appear black while protection is enabled
+6. On older Windows where fallback (WDA_MONITOR) is used, the window will appear black in remote sessions (RDP/VMs) and some screen-sharing environments

Happy to update the docs section with the exact wording you prefer.

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1a03404 and b3d5a94.

📒 Files selected for processing (12)
  • docs/src/content/docs/changelog.mdx (1 hunks)
  • docs/src/content/docs/learn/windows.mdx (1 hunks)
  • v3/UNRELEASED_CHANGELOG.md (1 hunks)
  • v3/examples/window/main.go (1 hunks)
  • v3/pkg/application/webview_window.go (2 hunks)
  • v3/pkg/application/webview_window_darwin.go (2 hunks)
  • v3/pkg/application/webview_window_linux.go (1 hunks)
  • v3/pkg/application/webview_window_options.go (1 hunks)
  • v3/pkg/application/webview_window_windows.go (2 hunks)
  • v3/pkg/application/window.go (1 hunks)
  • v3/pkg/w32/user32.go (1 hunks)
  • v3/pkg/w32/wda.go (1 hunks)
🧰 Additional context used
🧠 Learnings (10)
📚 Learning: 2024-09-20T23:34:29.841Z
Learnt from: nixpare
PR: wailsapp/wails#3763
File: v3/examples/keybindings/main.go:16-17
Timestamp: 2024-09-20T23:34:29.841Z
Learning: In the codebase, `application.Options.KeyBindings` uses the `application.Window` type, whereas `application.WebviewWindowOptions.KeyBindings` uses `*application.WebviewWindow`. This is intentional and acceptable.

Applied to files:

  • v3/pkg/application/webview_window_linux.go
  • v3/pkg/application/webview_window_options.go
  • v3/examples/window/main.go
  • v3/pkg/application/webview_window.go
  • docs/src/content/docs/learn/windows.mdx
  • v3/pkg/application/webview_window_darwin.go
  • v3/pkg/application/webview_window_windows.go
📚 Learning: 2024-10-08T22:11:37.054Z
Learnt from: nixpare
PR: wailsapp/wails#3763
File: v3/pkg/application/application_options.go:93-93
Timestamp: 2024-10-08T22:11:37.054Z
Learning: The `KeyBindings` property of `application.Option` uses the `application.Window` type, while `application.WebviewWindowOptions` still accepts `*application.WebviewWindow`, and this is intentional.

Applied to files:

  • v3/pkg/application/webview_window_options.go
  • v3/pkg/application/webview_window.go
  • docs/src/content/docs/learn/windows.mdx
📚 Learning: 2024-09-21T13:34:24.145Z
Learnt from: nixpare
PR: wailsapp/wails#3763
File: v3/pkg/application/webview_window_bindings_darwin.h:0-0
Timestamp: 2024-09-21T13:34:24.145Z
Learning: In this codebase, typedefs for window references (like replacing `void *` with `WindowRef`) are not preferred; using `void *` is acceptable.

Applied to files:

  • v3/pkg/w32/user32.go
📚 Learning: 2025-08-08T09:13:16.884Z
Learnt from: APshenkin
PR: wailsapp/wails#4480
File: v2/internal/frontend/desktop/darwin/message.h:17-19
Timestamp: 2025-08-08T09:13:16.884Z
Learning: In Wails v2 bindings origin verification, processBindingMessage intentionally has different signatures across platforms: Darwin includes an isMainFrame bool (WKWebKit provides it), Linux uses two params (message, source) as WebKitGTK doesn’t expose main-frame info there, and Windows handles origin checks in Go via WebView2 sender/args without a C bridge. This divergence is acceptable/expected per maintainer (APshenkin).

Applied to files:

  • v3/pkg/w32/user32.go
  • v3/examples/window/main.go
  • v3/pkg/application/webview_window_darwin.go
📚 Learning: 2025-04-29T23:54:07.488Z
Learnt from: popaprozac
PR: wailsapp/wails#4256
File: v2/internal/frontend/desktop/linux/notifications.go:27-28
Timestamp: 2025-04-29T23:54:07.488Z
Learning: In Wails v2, unlike v3-alpha which has a `ServiceShutdown` method for services, there is no standardized teardown pattern for frontend implementations. When implementing features that require cleanup (like goroutines or resources), add explicit cleanup methods (e.g., `CleanupNotifications()`) that handle resource release, context cancellation, and connection closure.

Applied to files:

  • docs/src/content/docs/changelog.mdx
📚 Learning: 2025-08-08T13:15:20.287Z
Learnt from: APshenkin
PR: wailsapp/wails#4484
File: v2/internal/frontend/utils/urlValidator.go:25-31
Timestamp: 2025-08-08T13:15:20.287Z
Learning: In Wails v2 (PR wailsapp/wails#4484), for BrowserOpenURL URL validation (v2/internal/frontend/utils/urlValidator.go), maintainers (APshenkin) prefer not to restrict schemes to an http/https allowlist because supported schemes may vary. The allowlist suggestion is declined; continue with the existing denylist approach and generic validation.

Applied to files:

  • docs/src/content/docs/changelog.mdx
📚 Learning: 2024-10-08T22:11:37.054Z
Learnt from: leaanthony
PR: wailsapp/wails#3763
File: v3/examples/window/main.go:472-475
Timestamp: 2024-10-08T22:11:37.054Z
Learning: In `v3/examples/window/main.go`, `time.Sleep` is used within a goroutine and does not block the UI thread.

Applied to files:

  • v3/examples/window/main.go
  • v3/pkg/w32/wda.go
  • docs/src/content/docs/learn/windows.mdx
📚 Learning: 2025-01-24T22:41:18.566Z
Learnt from: leaanthony
PR: wailsapp/wails#4031
File: v3/pkg/application/menu.go:199-202
Timestamp: 2025-01-24T22:41:18.566Z
Learning: In the Wails menu system (v3/pkg/application/menu.go), shared state between menus is intentionally designed and desirable. Methods like `Append()` and `Prepend()` should maintain shared references to menu items rather than creating deep copies.

Applied to files:

  • v3/examples/window/main.go
📚 Learning: 2024-09-30T06:14:32.602Z
Learnt from: leaanthony
PR: wailsapp/wails#3763
File: v3/internal/commands/appimage_testfiles/main.go:295-299
Timestamp: 2024-09-30T06:14:32.602Z
Learning: In `v3/internal/commands/appimage_testfiles/main.go`, `time.Sleep` is used within a goroutine and does not block the UI thread.

Applied to files:

  • v3/examples/window/main.go
📚 Learning: 2024-09-21T09:56:48.126Z
Learnt from: nixpare
PR: wailsapp/wails#3763
File: v3/pkg/application/webview_panel_darwin.go:88-89
Timestamp: 2024-09-21T09:56:48.126Z
Learning: Safety checks for `p.nsPanel` are performed in the `SetFloating` method of `WebviewPanel`, following the `WebviewWindow` and `macosWebviewWindow` implementations and code style.

Applied to files:

  • v3/pkg/application/webview_window_darwin.go
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Run Go Tests v3 (ubuntu-latest, 1.24)
  • GitHub Check: Run Go Tests v3 (windows-latest, 1.24)
🔇 Additional comments (3)
v3/pkg/application/window.go (1)

91-91: SetContentProtection added to Window – internal and platform implementations verified

Verified:

  • Internal implementation:
    • WebviewWindow implements SetContentProtection (v3/pkg/application/webview_window.go:524). No other Window implementers were found.
  • macOS (Darwin):
    • The C bridge for content protection uses dispatch_async(dispatch_get_main_queue(), …) in v3/pkg/application/webview_window_darwin.go (lines 397–405).
  • Windows:
    • SetWindowDisplayAffinity in v3/pkg/w32/wda.go falls back to WDA_MONITOR for Windows < 10 2004 (build 19041).
    • It’s invoked in v3/pkg/application/webview_window_windows.go (lines 2450–2454).
  • Documentation:
    • Updated in docs/src/content/docs/learn/windows.mdx (mentions and examples of SetContentProtection(true/false)).

Next step:

  • If your JS/TS runtime or TypeScript definitions expose the Window API, please confirm that SetContentProtection is surfaced there as well.
v3/pkg/application/webview_window_darwin.go (1)

821-833: Content Protection via NSWindowSharingType Is Ineffective on Modern macOS

Apple now documents that NSWindowSharingNone is a legacy constant and no longer prevents a window from being shared or captured, and NSWindowSharingReadOnly never did. As a result, swapping these values has no effect on today’s screen-recording or sharing APIs.

• Remove or deprecate setContentProtection()’s use of setSharingType: entirely, or clearly document that it does not guarantee privacy.
• If you choose to keep it, at minimum wrap the call in a main-thread dispatch and add a comment describing the limitation:

dispatch_async(dispatch_get_main_queue(), ^{
    // NOTE: Neither NSWindowSharingNone nor NSWindowSharingReadOnly
    // prevents screen capture on modern macOS. This API is effectively a no-op.
    [window setSharingType: enabled ? NSWindowSharingReadOnly : NSWindowSharingNone];
});

• For true capture prevention, consider platform-supported alternatives (e.g. ScreenCaptureKit, CoreGraphics window-image options, or CA filters) and document the trade-offs clearly.

Likely an incorrect or invalid review comment.

v3/pkg/application/webview_window_windows.go (1)

383-385: Good integration point for applying content protection

Applied immediately after CreateWindowEx and before Chromium init, which is ideal. No ordering concerns spotted.

Comment thread v3/pkg/application/webview_window_darwin.go
Comment thread v3/pkg/application/webview_window_options.go
Comment thread v3/pkg/application/webview_window_windows.go
Comment thread v3/pkg/application/webview_window.go
Comment thread v3/pkg/application/webview_window.go
Comment thread v3/pkg/w32/user32.go Outdated
Comment thread v3/pkg/w32/wda.go
Comment thread v3/pkg/application/webview_window_darwin.go

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

🧹 Nitpick comments (1)
v3/tasks/cleanup/cleanup.go (1)

28-30: Nit: clarify descriptions.

Tighten the wording for consistency and clarity.

- {Type: "exact", Pattern: "myapp.ARCHLINUX", TargetFiles: true, Description: "Linux ARCHLINUX package"},
- {Type: "exact", Pattern: "myapp.DEB", TargetFiles: true, Description: "Linux DEB package"},
- {Type: "exact", Pattern: "myapp.RPM", TargetFiles: true, Description: "Linux RPM package"},
+ {Type: "exact", Pattern: "myapp.ARCHLINUX", TargetFiles: true, Description: "Arch Linux package artifact"},
+ {Type: "exact", Pattern: "myapp.DEB",        TargetFiles: true, Description: "DEB package artifact"},
+ {Type: "exact", Pattern: "myapp.RPM",        TargetFiles: true, Description: "RPM package artifact"},
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7cf37a9 and 1330ad5.

📒 Files selected for processing (2)
  • v3/pkg/application/webview_window_windows.go (2 hunks)
  • v3/tasks/cleanup/cleanup.go (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • v3/pkg/application/webview_window_windows.go
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
  • GitHub Check: Run Go Tests v3 (macos-latest, 1.24)
  • GitHub Check: Run Go Tests v3 (windows-latest, 1.24)
  • GitHub Check: Run Go Tests v3 (ubuntu-latest, 1.24)
  • GitHub Check: semgrep/ci
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: Analyze (go)
  • GitHub Check: semgrep-cloud-platform/scan
  • GitHub Check: Cloudflare Pages
🔇 Additional comments (6)
v3/tasks/cleanup/cleanup.go (6)

22-22: No-op formatting change.


25-25: No-op formatting change.


31-31: No-op formatting change.


34-34: No-op formatting change.


97-97: No-op change (closing brace).


28-30: Ensure cleanup patterns match actual package filenames
The current exact-match rules in v3/tasks/cleanup/cleanup.go assume uppercase extensions and no version/arch metadata. Most builders emit lowercase “.deb”/“.rpm” files (often with version and arch in the name), so these patterns may never match:

• File: v3/tasks/cleanup/cleanup.go (lines 28–30)
• Current rules:

{Type: "exact", Pattern: "myapp.ARCHLINUX", TargetFiles: true, Description: "Linux ARCHLINUX package"},
{Type: "exact", Pattern: "myapp.DEB",       TargetFiles: true, Description: "Linux DEB package"},
{Type: "exact", Pattern: "myapp.RPM",       TargetFiles: true, Description: "Linux RPM package"},

Please verify the filenames your packaging tests actually generate. If they use lowercase extensions and include version/arch, switch to suffix matches, for example:

-{Type: "exact", Pattern: "myapp.DEB", TargetFiles: true, Description: "Linux DEB package"},
-{Type: "exact", Pattern: "myapp.RPM", TargetFiles: true, Description: "Linux RPM package"},
+{Type: "suffix", Pattern: ".deb", TargetFiles: true, Description: "Linux DEB package"},
+{Type: "suffix", Pattern: ".rpm", TargetFiles: true, Description: "Linux RPM package"},

And adjust the ARCHLINUX rule similarly (e.g., “.pkg.tar.zst”). If your tests really do produce uppercase artifacts named “myapp.DEB”/“myapp.RPM”, you can leave the exact match in place.

Comment thread v3/tasks/cleanup/cleanup.go
leaanthony and others added 3 commits August 9, 2025 15:29
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
@leaanthony leaanthony merged commit 3f11d4e into v3-alpha Aug 9, 2025
10 of 12 checks passed
@leaanthony leaanthony deleted the v3-alpha-feature/content-protection branch August 9, 2025 07:12
@sonarqubecloud

sonarqubecloud Bot commented Aug 9, 2025

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
2 Security Hotspots

See analysis details on SonarQube Cloud

@coderabbitai coderabbitai Bot mentioned this pull request Sep 25, 2025
15 tasks
Grantmartin2002 pushed a commit to Grantmartin2002/wails that referenced this pull request Apr 29, 2026
* feat: Add Content Protection for Windows and macOS

- Prevents window contents from being captured by screen recording/sharing software
- Windows: Uses WDA_EXCLUDEFROMCAPTURE on Windows 10 2004+, falls back to WDA_MONITOR
- macOS: Uses NSWindowSharingType to set window as read-only for screen sharing
- Added ContentProtectionEnabled option to WebviewWindowOptions
- Added SetContentProtection() method for runtime control
- Added comprehensive documentation and example usage

* fix changelog.mdx

* Misc fixes

* Misc fixes

* Update v3/pkg/w32/user32.go

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* Remove debug line

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Documentation Improvements or additions to documentation Enhancement New feature or request go Pull requests that update Go code Linux MacOS size:L This PR changes 100-499 lines, ignoring generated files. v3-alpha Windows

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants