Skip to content

Basic clipboard support#19106

Merged
alice-i-cecile merged 107 commits into
bevyengine:mainfrom
ickshonpe:clipboard
Apr 23, 2026
Merged

Basic clipboard support#19106
alice-i-cecile merged 107 commits into
bevyengine:mainfrom
ickshonpe:clipboard

Conversation

@ickshonpe
Copy link
Copy Markdown
Contributor

@ickshonpe ickshonpe commented May 6, 2025

Objective

Add a platform-agnostic interface for interacting with the clipboard.

Solution

New crate bevy_clipboard with a ClipboardPlugin that adds a Clipboard resource. The clipboard is accessed using the methods fetch_text, fetch_image, set_text and set_image on the Clipboard resource. fetch_text returns a ClipboardRead with a poll_result method that's used to get the actual value once it's ready.

The windows and unix implementations both use the arboard crate. On windows the Clipboard resource is a unit struct and a new arboard clipboard instance is created and dropped for each clipboard access. On unix targets the Clipboard resource holds a clipboard instance it reuses each time. On both targets the fetch_* and set_* methods work instantly.

On wasm32 Clipboard is a unit struct. The fetch_text and set_text functions spawn async tasks. The task spawned by fetch_text updates the shared arc mutex option once the future is evaluated to get the clipboard text. There is no image support on wasm32.

Everything seems to work but it feels like the design is a bit clumsy and not very idiomatic. I don't tend to do much asynchronous programming, maybe a reviewer can suggest an improved construction.

I also added an alternative fetch_text_async function for async access that returns a Result<String, ClipboardError> future.

Notes

  • Doesn't support android targets yet.
  • The wasm32 implementation doesn't support images. It's much more complicated and probably best to left to a follow up.

Testing

The PR includes a basic example clipboard that can be used for testing.
The image display will only work if the image is already in the clipboard before the example starts.

ickshonpe added 4 commits May 6, 2025 23:58
Enabled with the `bevy_clipboard` feature.
Supports setting and getting text to and from the clipboard.
Only supports desktop targets.
Enabled with the `bevy_clipboard` feature.
Supports setting and getting text to and from the clipboard.
Only supports desktop targets.
@ickshonpe ickshonpe added C-Feature A new feature, making something new possible A-Utils Utility functions and types labels May 6, 2025
@alice-i-cecile alice-i-cecile added A-UI Graphical user interfaces, styles, layouts, and widgets A-Editor Graphical tools to make Bevy games X-Needs-SME This type of work requires an SME to approve it. S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels May 6, 2025
@alice-i-cecile
Copy link
Copy Markdown
Member

Marked as X-Controversial due to a new crate, but I strongly think we need this as part of the engine in some form. Both for games and the editor!

@mockersf
Copy link
Copy Markdown
Member

mockersf commented May 6, 2025

I don't like the crate for that which is pretty much just a resource wrapping arboard...

And not sure I like the fake resource that can't work on not supported platforms

Comment thread crates/bevy_clipboard/src/dummy.rs Outdated
Comment thread crates/bevy_clipboard/src/desktop.rs Outdated
&mut self,
text: T,
) -> Result<(), arboard::Error> {
arboard::Clipboard::new().and_then(|mut clipboard| clipboard.set_text(text))
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.

I think dropping the Clipboard may not work on Linux ?
See arboard's documentation about platform-specific behaviors (and also issue #88 and PR #89 for more info)

Copy link
Copy Markdown
Contributor Author

@ickshonpe ickshonpe May 7, 2025

Choose a reason for hiding this comment

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

Yeah seems like drop-after-use is only needed on windows.

Comment thread crates/bevy_clipboard/Cargo.toml Outdated
@ickshonpe
Copy link
Copy Markdown
Contributor Author

ickshonpe commented May 7, 2025

I don't like the crate for that which is pretty much just a resource wrapping arboard...

This PR is really trivial, but image and android and wasm support will add a lot more complexity. I'm being lazy here, I've got way too many things I working on atm so I was thinking if I just get desktop text clipboard support going someone else will pick this up and fill out the rest of the implementation.

I'm not sure it's an important enough feature to deserve its own crate, but I'm not sure if it belongs in any of the exis
ting crates either. Maybe bevy_window but using the clipboard doesn't require a window.

And not sure I like the fake resource that can't work on not supported platforms

The intent is that you can only use the clipboard with a ResMut<Clipboard> to ensure that access is exclusive. Maybe there's a better way to implement it, I'm not sure.

ickshonpe and others added 7 commits May 7, 2025 12:06
Co-authored-by: Gilles Henaux <ghx_github_priv@fastmail.com>
* On unix targets an instance of `arboard::Clipboard` is stored in the `Clipboard` resource.
* Removed the desktop and dummy modules.
* Made `arboard` dependency conditional.
@Henauxg
Copy link
Copy Markdown
Contributor

Henauxg commented May 7, 2025

For crates candidates, I've had a look and did not find much either. Doesn't fit in bevy_text, nor bevy_input. Could always force it in bevy_utils but that's no great either. There's maybe bevy_app which already has a TerminalCtrlCHandlerPlugin plugin using the ctrlc dependency, but I'm not sure that tying clipboard to App is a good choice.

There's a potential savior in bevy_winit. I've seen that clipboard handling might be on the roadmap for 0.31 or later ? See #162 and #2156
So it may make sense to snuck it into bevy_winit, while waiting for it to be available directly from winit ?

@ickshonpe
Copy link
Copy Markdown
Contributor Author

For crates candidates, I've had a look and did not find much either. Doesn't fit in bevy_text, nor bevy_input. Could always force it in bevy_utils but that's no great either. There's maybe bevy_app which already has a TerminalCtrlCHandlerPlugin plugin using the ctrlc dependency, but I'm not sure that tying clipboard to App is a good choice.

There's a potential savior in bevy_winit. I've seen that clipboard handling might be on the roadmap for 0.31 or later ? See #162 and #2156 So it may make sense to snuck it into bevy_winit, while waiting for it to be available directly from winit ?

It'd be ideal if winit just supported it and we didn't have to do anything but I don't like the idea of adding it to the winit crate before they have some built in support, it seems like a lie. And it might still need a separate solution when targeting wasm32?

Comment thread crates/bevy_text/src/text_edit.rs Outdated
@alice-i-cecile
Copy link
Copy Markdown
Member

Okay, I think this is finally ready!

  1. The image support functions in general, but for some reason does not like my screenshot snip tool on PopOS.
  2. System clipboard support is now fully operational, including on web. It needed some fanciness to support polling properly, but I'm really quite pleased with the final architecture.

@ickshonpe, this is ready to merge once my changes have your approval.

@alice-i-cecile alice-i-cecile added this to the 0.19 milestone Apr 23, 2026
Comment thread examples/ui/clipboard.rs Outdated
@@ -0,0 +1,227 @@
//! This example demonstrates accessing the clipboard to retrieve and display text.
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yeah I made this example quickly without any thought just as proof it works. It's not necessary
once the clipboard is hooked up to widgets that can use it.

Comment thread crates/bevy_internal/Cargo.toml
// Defaults selected to match `Text::default()`
editor: PlainEditor::new(100.),
pending_edits: Vec::new(),
pending_paste: None,
Copy link
Copy Markdown
Contributor Author

@ickshonpe ickshonpe Apr 23, 2026

Choose a reason for hiding this comment

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

In bevy_ui_text_input it queues a PasteDeferred(ClipboardRead) in the editor actions buffer so there isn't a need to store it on a field. Then if the result is still pending it doesn't process any more actions and leaves the PasteDeferred on top of the queue to be processed again the next frame. The pending field approach seems a bit simpler, but we might want to switch to the other approach later as it seems unpleasant having bevy_text depend on bevy_clipboard and there might be other reasons we'd want to handle cut and paste at the widget level (pasting images inline into a text input maybe?).

Copy link
Copy Markdown
Contributor Author

@ickshonpe ickshonpe Apr 23, 2026

Choose a reason for hiding this comment

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

I can't remember what they were right now, but I'm certain there were other advantages to managing the TextEdit queue at the widget level, not at a lower level from bevy_text. It's out of scope for this PR though, the pending_paste design is fine for now.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Yeah, happy to explore that in follow-up. I agree that bevy_text -> bevy_clipboard is a bit unpleasant as a dependency.

@ickshonpe
Copy link
Copy Markdown
Contributor Author

can't approve my own pull request, but 👍

Copy link
Copy Markdown
Contributor

@viridia viridia left a comment

Choose a reason for hiding this comment

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

Re-approving

@alice-i-cecile alice-i-cecile added this pull request to the merge queue Apr 23, 2026
@alice-i-cecile alice-i-cecile added S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it and removed S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels Apr 23, 2026
@github-project-automation github-project-automation Bot moved this to Needs SME Triage in UI Apr 23, 2026
Merged via the queue into bevyengine:main with commit 41f170c Apr 23, 2026
44 checks passed
@github-project-automation github-project-automation Bot moved this from Needs SME Triage to Done in UI Apr 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-Editor Graphical tools to make Bevy games A-UI Graphical user interfaces, styles, layouts, and widgets A-Utils Utility functions and types C-Feature A new feature, making something new possible D-Modest A "normal" level of difficulty; suitable for simple features or challenging fixes S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it X-Needs-SME This type of work requires an SME to approve it.

Projects

Status: Widget-ready
Status: Done

Development

Successfully merging this pull request may close these issues.

10 participants