Skip to content

Generic clipboard storage#11407

Merged
eira-fransham merged 22 commits intoslint-ui:feature/drag-and-dropfrom
eira-fransham:11399-generic-clipboard
Apr 21, 2026
Merged

Generic clipboard storage#11407
eira-fransham merged 22 commits intoslint-ui:feature/drag-and-dropfrom
eira-fransham:11399-generic-clipboard

Conversation

@eira-fransham
Copy link
Copy Markdown
Contributor

Closes #11399 (that issue also explains the research and design decisions).

This is an initial implementation of an API for the clipboard that can support arbitrary MIME types. For now, the functionality is unchanged - only strings can be stored/retrieved from the clipboard. Actually handling multiple types is left for future work.

Copy link
Copy Markdown
Member

@LeonMatthes LeonMatthes left a comment

Choose a reason for hiding this comment

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

Just some initial thoughts.

In summary, I think we should try to limit the API surface of this where possible.
Maybe we can just use strings for mime types for now? That's probably what they need to end up as in Slint code anyhow.

Comment thread internal/core/clipboard.rs Outdated
Comment thread internal/core/clipboard.rs Outdated
Comment thread internal/core/clipboard.rs Outdated
Comment thread internal/core/clipboard/mod.rs
Comment thread internal/core/clipboard/mod.rs Outdated
Comment thread internal/core/clipboard.rs Outdated
Comment thread internal/core/clipboard/mod.rs
@eira-fransham eira-fransham force-pushed the 11399-generic-clipboard branch from 5335fcd to a734ee0 Compare April 20, 2026 09:05
@tronical
Copy link
Copy Markdown
Member

Since there's still a bit of confusing, I decided to write up what I think a minimal API would be that

(1) is easy to use for people who want to read/write to the clipboard and create/consume dnd data in the future
(2) permits lazy retrieval for backend implementations when needed
(3) Is straight-forward to map to our other supported programming languages

pub trait Platform {
   ...
    fn set_clipboard_text(&self, _text: &str, _clipboard: Clipboard) {
        self.set_clipboard_data(MimeData::default().with_plain_text(_text), _clipboard);
    }

    fn clipboard_text(&self, _clipboard: Clipboard) -> Option<String> {
        self.clipboard_data(_clipboard).and_then(|data| data.fetch_as_plain_text())
    }

    fn set_clipboard_data(&self, _data: MimeData, _clipboard: Clipboard) {}

    fn clipboard_data(&self, _clipboard: Clipboard) -> Option<&MimeData> {
        None
    }
   ...
}

enum MimeDataEntry {
    Bytes(Box<[u8]>),
    Provider(Box<dyn Fn() -> Box<[u8]> + Send + Sync>),
}

#[derive(Default, Clone)]
pub struct MimeData {
    entries: std::collections::HashMap<String, alloc::sync::Arc<MimeDataEntry>>,
}

impl MimeData {
    pub fn with_bytes(self, mime_type: impl Into<String>, data: impl Into<Box<[u8]>>) -> Self {
        todo!();
        self
    }

    pub fn with_provider(
        self,
        mime_type: impl Into<String>,
        provider: impl Fn() -> Box<[u8]> + Send + Sync + 'static,
    ) -> Self {
        todo!();
        self
    }

    pub fn with_plain_text(self, text: impl Into<String>) -> Self {
        self.with_bytes("text/plain", text.into().into_bytes().into_boxed_slice())
    }

    pub fn mime_types(&self) -> impl Iterator<Item = &str> {
        self.entries.keys().map(|s| s.as_str())
    }

    pub fn fetch_bytes(&self, mime_type: &str) -> Option<Box<[u8]>> {
        self.entries.get(mime_type).map(|entry| match &**entry {
            MimeDataEntry::Bytes(bytes) => bytes.clone(),
            MimeDataEntry::Provider(provider) => provider(),
        })
    }

    pub fn fetch_as_plain_text(&self) -> Option<String> {
        self.fetch_bytes("text/plain;charset=utf-8")
            .or_else(|| self.fetch_bytes("text/plain"))
            .and_then(|bytes| String::from_utf8(bytes.to_vec()).ok())
    }
}

This is minimal. But we can extend it in the future to support async retrieval, add more convenience functions, as well as the ability to store an Rc<dyn Any>.

Names also subject to discussion, but I think this captures the core of what I feel is a minimal API that captures what I feel we need.

@eira-fransham eira-fransham changed the base branch from master to feature/drag-and-drop April 21, 2026 08:03
@eira-fransham
Copy link
Copy Markdown
Contributor Author

eira-fransham commented Apr 21, 2026

@tronical Just to serialise the discussion we had on Mattermost so it's visible on this PR later:

  • The design you proposed locks us into a fair few design decisions quite early
  • Either the current design or your proposed design are enough to get started with for now
  • We might still want to design the system that way, but we shouldn't merge that design or the design as-implemented in this PR to master, as there are still disagreements about the right approach. Since most of that disagreement hinges on future work that hasn't been built yet, it's better to merge this to a feature branch

Is there anything else that I missed?

@eira-fransham eira-fransham merged commit 584ddbb into slint-ui:feature/drag-and-drop Apr 21, 2026
91 of 95 checks passed
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.

Use a custom data type for clipboard data which better matches platform semantics

3 participants