Skip to content

Implement Clipboard Essentials API#171

Open
jsuarezruiz wants to merge 12 commits into
mainfrom
essentials-clipboard
Open

Implement Clipboard Essentials API#171
jsuarezruiz wants to merge 12 commits into
mainfrom
essentials-clipboard

Conversation

@jsuarezruiz
Copy link
Copy Markdown
Member

@jsuarezruiz jsuarezruiz commented Mar 23, 2026

Changes:

  • Clipboard (IClipboard): Full implementation with platform-specific paths for desktop (Avalonia TopLevel.Clipboard + Window.Activated change detection) and browser (navigator.clipboard via [JSImport])

Tested:
image

Copilot AI review requested due to automatic review settings March 23, 2026 09:29
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR adds missing “Essentials” building blocks for the Avalonia backend by implementing cross-platform Clipboard support and a MainThread-compatible dispatcher API (with an MSBuild alias to keep existing MainThread.* call sites working on Avalonia TFMs).

Changes:

  • Implement AvaloniaClipboard with desktop (TopLevel clipboard + window activation polling) and browser (JSImport navigator.clipboard) backends.
  • Add AvaloniaMainThread backed by Dispatcher.UIThread, plus a conditional MainThread alias on net11.0 / net11.0-browser.
  • Add a ControlGallery sample page and basic unit tests/documentation updates.

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
tests/Avalonia.Controls.Maui.Essentials.Tests/AvaloniaClipboardTests.cs Adds basic null-TopLevel and event-subscription tests for clipboard.
STATUS-ESSENTIALS.md Marks Clipboard + AvaloniaMainThread APIs as implemented and updates MainThread note.
src/Avalonia.Controls.Maui.targets Adds conditional MSBuild Using alias mapping MainThreadAvaloniaMainThread for Avalonia TFMs.
src/Avalonia.Controls.Maui.Essentials/README.md Documents Clipboard and MainThread availability/usage guidance.
src/Avalonia.Controls.Maui.Essentials/MauiEssentialsBuilderExtensions.cs Registers Clipboard.Default with the Avalonia implementation.
src/Avalonia.Controls.Maui.Essentials/MainThread/AvaloniaMainThread.cs Introduces dispatcher-backed MainThread-compatible API surface.
src/Avalonia.Controls.Maui.Essentials/Clipboard/ClipboardInterop.Browser.cs Adds JSImport bindings for navigator.clipboard APIs.
src/Avalonia.Controls.Maui.Essentials/Clipboard/AvaloniaClipboard.cs Adds MAUI IClipboard implementation and shared state/event wiring.
src/Avalonia.Controls.Maui.Essentials/Clipboard/AvaloniaClipboard.Default.cs Desktop clipboard implementation using TopLevel.Clipboard + activation checks.
src/Avalonia.Controls.Maui.Essentials/Clipboard/AvaloniaClipboard.Browser.cs Browser clipboard implementation using JSImport interop.
samples/ControlGallery/ControlGallery/Pages/ClipboardPage.xaml Adds UI for clipboard copy/paste/HasText/event demo.
samples/ControlGallery/ControlGallery/Pages/ClipboardPage.xaml.cs Wires the sample page to Clipboard + MainThread APIs.
samples/ControlGallery/ControlGallery/MainPage.xaml.cs Registers the new Clipboard sample in the gallery navigation.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/Avalonia.Controls.Maui.Essentials/Clipboard/AvaloniaClipboard.cs Outdated
Comment thread src/Avalonia.Controls.Maui.Essentials/Clipboard/AvaloniaClipboard.Default.cs Outdated
Comment thread src/Avalonia.Controls.Maui.Essentials/MainThread/AvaloniaMainThread.cs Outdated
Copy link
Copy Markdown
Collaborator

@drasticactions drasticactions left a comment

Choose a reason for hiding this comment

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

We shouldn't introduce a hack for MainThread, but Clipboard is fine. If you remove the MainThread code, then I'm 👍 .

Comment thread src/Avalonia.Controls.Maui.targets Outdated
Comment thread src/Avalonia.Controls.Maui.Essentials/Clipboard/AvaloniaClipboard.Browser.cs Outdated
Comment on lines +52 to +57
if (_platformProvider.GetTopLevel() is Window window)
{
window.Activated += OnWindowActivated;
_isSubscribed = true;
}
}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I'm not sure if this is correct. EnsureSubscribedToWindowActivation runs whenever GetClipboard is called, which occurs when a user explicitly calls a clipboard API. If they had an event handle for ClipboardContentChanged, it will only ever run if they happen to call one of these methods first.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

EnsureSubscribed now runs from the ClipboardContentChanged add accessor instead of GetClipboard.


if (_platformProvider.GetTopLevel() is Window window)
{
window.Activated += OnWindowActivated;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

window.Activated is attached to, but nothing disposes of it.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Fixed. Applied changes and storing the subscribed Window reference and unsubscribing both Activated and Closed handlers in OnWindowClosed.

UpdateState(currentText);

if (changed)
ClipboardContentChanged?.Invoke(this, EventArgs.Empty);
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

If you're in the app and you copy text from another text field, without activating the window, this event won't get invoked. It only activates when the window is activated.

@jsuarezruiz jsuarezruiz changed the title Implement Clipboard and MainThread Essentials APIs Implement Clipboard Essentials API Mar 23, 2026
Comment thread Directory.Build.props
<!-- Avalonia.FreeDesktop still declares the vulnerable version; force the patched one. -->
<PackageReference Include="Tmds.DBus.Protocol" Version="0.92.0" />
</ItemGroup>

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This shouldn't be needed with the version bumps made elsewhere, and if something like this happens in the future, we should always fix the root versions rather than work around them.

}

/// <inheritdoc/>
public bool HasText => _hasText;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Checking in the maui repo, these values are computed when called via OS values, (Ex, https://github.com/dotnet/maui/blob/388b82f166d937c69a4553556b0042f441eadcd6/src/Essentials/src/Clipboard/Clipboard.ios.cs#L20-L21)

Here, it's cached, so as far as I can tell, SetTextAsync, GetTextAsync, or Activated would need to be called to update the value. Since Activate should be called when you touch the window, that might be fine, but there might be a better way to handle this. @maxkatz6 @MrJul, what do you think about this?

Copy link
Copy Markdown
Member

@maxkatz6 maxkatz6 Apr 27, 2026

Choose a reason for hiding this comment

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

With async-only nature of current clipboard implementation, it would be hard to implement something like this.
On desktop, you we can use DispatcherFrame hack to (probably) safely run async code in-sync.

Otherwise, always returning true might be the safest bet (there is never a guarantee clipboard is not cleared between HasText and GeText calls anyway).

We need to have a new API on the Avalonia side, for clipboard changed events.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

We need to have a new API on the Avalonia side, for clipboard changed events.

Yeah, that sounds good. It may be best to hold off on this PR for now and implement it in Avalonia first, then here. I don't think this is so important that we need to hack around it right now for the sake of the previews. We have time to implement it properly in Avalonia and use that instead.

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.

4 participants