ashpd/desktop/
clipboard.rs

1//! Interact with the clipboard.
2//!
3//! The portal is mostly meant to be used along with
4//! [`RemoteDesktop`]
5
6use std::collections::HashMap;
7
8use futures_util::{Stream, StreamExt};
9use zbus::zvariant::{DeserializeDict, OwnedFd, OwnedObjectPath, SerializeDict, Type, Value};
10
11use super::{remote_desktop::RemoteDesktop, Session};
12use crate::{proxy::Proxy, Result};
13
14#[derive(Debug, Type, SerializeDict)]
15#[zvariant(signature = "dict")]
16struct SetSelectionOptions<'a> {
17    mime_types: &'a [&'a str],
18}
19
20#[derive(Debug, Type, DeserializeDict)]
21#[zvariant(signature = "dict")]
22/// The details of a new clipboard selection.
23pub struct SelectionOwnerChanged {
24    mime_types: Option<Vec<String>>,
25    session_is_owner: Option<bool>,
26}
27
28impl SelectionOwnerChanged {
29    /// Whether the session is the owner of the clipboard selection or not.
30    pub fn session_is_owner(&self) -> Option<bool> {
31        self.session_is_owner
32    }
33
34    /// A list of mime types the new clipboard has content for.
35    pub fn mime_types(&self) -> Vec<String> {
36        self.mime_types.clone().unwrap_or_default()
37    }
38}
39
40#[doc(alias = "org.freedesktop.portal.Clipboard")]
41/// Wrapper of the DBus interface: [`org.freedesktop.portal.Clipboard`](https://flatpak.github.io/xdg-desktop-portal/docs/doc-org.freedesktop.portal.Clipboard.html).
42pub struct Clipboard<'a>(Proxy<'a>);
43
44impl<'a> Clipboard<'a> {
45    /// Create a new instance of [`Clipboard`].
46    pub async fn new() -> Result<Clipboard<'a>> {
47        Ok(Self(
48            Proxy::new_desktop("org.freedesktop.portal.Clipboard").await?,
49        ))
50    }
51
52    /// # Specifications
53    ///
54    /// See also [`RequestClipboard`](https://flatpak.github.io/xdg-desktop-portal/docs/doc-org.freedesktop.portal.Clipboard.html#org-freedesktop-portal-clipboard-requestclipboard).
55    #[doc(alias = "RequestClipboard")]
56    pub async fn request(&self, session: &Session<'_, RemoteDesktop<'_>>) -> Result<()> {
57        let options: HashMap<&str, Value<'_>> = HashMap::default();
58        self.0
59            .call_method("RequestClipboard", &(session, options))
60            .await?;
61        Ok(())
62    }
63
64    /// # Specifications
65    ///
66    /// See also [`SetSelection`](https://flatpak.github.io/xdg-desktop-portal/docs/doc-org.freedesktop.portal.Clipboard.html#org-freedesktop-portal-clipboard-setselection).
67    #[doc(alias = "SetSelection")]
68    pub async fn set_selection(
69        &self,
70        session: &Session<'_, RemoteDesktop<'_>>,
71        mime_types: &[&str],
72    ) -> Result<()> {
73        let options = SetSelectionOptions { mime_types };
74        self.0
75            .call::<()>("SetSelection", &(session, options))
76            .await?;
77
78        Ok(())
79    }
80
81    /// # Specifications
82    ///
83    /// See also [`SelectionWrite`](https://flatpak.github.io/xdg-desktop-portal/docs/doc-org.freedesktop.portal.Clipboard.html#org-freedesktop-portal-clipboard-selectionwrite).
84    #[doc(alias = "SelectionWrite")]
85    pub async fn selection_write(
86        &self,
87        session: &Session<'_, RemoteDesktop<'_>>,
88        serial: u32,
89    ) -> Result<OwnedFd> {
90        let fd = self
91            .0
92            .call::<OwnedFd>("SelectionWrite", &(session, serial))
93            .await?;
94        Ok(fd)
95    }
96
97    /// # Specifications
98    ///
99    /// See also [`SelectionWriteDone`](https://flatpak.github.io/xdg-desktop-portal/docs/doc-org.freedesktop.portal.Clipboard.html#org-freedesktop-portal-clipboard-selectionwritedone).
100    #[doc(alias = "SelectionWriteDone")]
101    pub async fn selection_write_done(
102        &self,
103        session: &Session<'_, RemoteDesktop<'_>>,
104        serial: u32,
105        success: bool,
106    ) -> Result<()> {
107        self.0
108            .call("SelectionWriteDone", &(session, serial, success))
109            .await
110    }
111
112    /// # Specifications
113    ///
114    /// See also [`SelectionRead`](https://flatpak.github.io/xdg-desktop-portal/docs/doc-org.freedesktop.portal.Clipboard.html#org-freedesktop-portal-clipboard-selectionread).
115    #[doc(alias = "SelectionRead")]
116    pub async fn selection_read(
117        &self,
118        session: &Session<'_, RemoteDesktop<'_>>,
119        mime_type: &str,
120    ) -> Result<OwnedFd> {
121        let fd = self
122            .0
123            .call::<OwnedFd>("SelectionRead", &(session, mime_type))
124            .await?;
125        Ok(fd)
126    }
127
128    /// Notifies the session that the clipboard selection has changed.
129    /// # Specifications
130    ///
131    /// See also [`SelectionOwnerChanged`](https://flatpak.github.io/xdg-desktop-portal/docs/doc-org.freedesktop.portal.Clipboard.html#org-freedesktop-portal-clipboard-selectionownerchanged).
132    #[doc(alias = "SelectionOwnerChanged")]
133    pub async fn receive_selection_owner_changed(
134        &self,
135    ) -> Result<impl Stream<Item = (Session<RemoteDesktop>, SelectionOwnerChanged)>> {
136        Ok(self
137            .0
138            .signal::<(OwnedObjectPath, SelectionOwnerChanged)>("SelectionOwnerChanged")
139            .await?
140            .filter_map(|(p, o)| async move { Session::new(p).await.map(|s| (s, o)).ok() }))
141    }
142
143    /// # Specifications
144    ///
145    /// See also [`SelectionTransfer`](https://flatpak.github.io/xdg-desktop-portal/docs/doc-org.freedesktop.portal.Clipboard.html#org-freedesktop-portal-clipboard-selectiontransfer).
146    #[doc(alias = "SelectionTransfer")]
147    pub async fn receive_selection_transfer(
148        &self,
149    ) -> Result<impl Stream<Item = (Session<RemoteDesktop>, String, u32)>> {
150        Ok(self
151            .0
152            .signal::<(OwnedObjectPath, String, u32)>("SelectionTransfer")
153            .await?
154            .filter_map(|(p, mime_type, serial)| async move {
155                Session::new(p)
156                    .await
157                    .map(|session| (session, mime_type, serial))
158                    .ok()
159            }))
160    }
161}
162
163impl<'a> std::ops::Deref for Clipboard<'a> {
164    type Target = zbus::Proxy<'a>;
165
166    fn deref(&self) -> &Self::Target {
167        &self.0
168    }
169}