search_provider/
result_metadata.rs

1#[cfg(feature = "gdk")]
2use gdk::prelude::*;
3use serde::Serialize;
4use zbus::zvariant::{SerializeDict, Type};
5
6use crate::ResultID;
7
8/// Detailed information of a [`ResultID`].
9#[derive(SerializeDict, Type, Debug, Default)]
10#[zvariant(signature = "dict")]
11pub struct ResultMeta {
12    id: ResultID,
13    name: String,
14    description: Option<String>,
15    #[zvariant(rename = "clipboardText")]
16    clipboard_text: Option<String>,
17    icon: Option<zbus::zvariant::OwnedValue>,
18    gicon: Option<String>,
19    #[zvariant(rename = "icon-data")]
20    icon_data: Option<IconData>,
21}
22
23impl ResultMeta {
24    pub fn builder(id: ResultID, name: &str) -> ResultMetaBuilder {
25        ResultMetaBuilder::new(id, name)
26    }
27}
28
29/// A struct wrapping the required information to re-construct an icon with
30/// [`gdk-pixbuf`](https://gtk-rs.org/gtk-rs-core/stable/0.14/docs/gdk_pixbuf/index.html).
31///
32/// You can make use of the `pixbuf` feature that implements `From<gdk_pixbuf::Pixbuf> for IconData`.
33#[derive(Debug, Type, Serialize)]
34pub struct IconData {
35    pub width: i32,
36    pub height: i32,
37    pub rowstride: i32,
38    pub has_alpha: bool,
39    pub bits_per_sample: i32,
40    pub n_channels: i32,
41    pub data: Vec<u8>,
42}
43
44#[cfg(feature = "gdk-pixbuf")]
45impl From<&gdk_pixbuf::Pixbuf> for IconData {
46    fn from(pixbuf: &gdk_pixbuf::Pixbuf) -> Self {
47        let data = pixbuf.read_pixel_bytes();
48        Self {
49            width: pixbuf.width(),
50            height: pixbuf.height(),
51            rowstride: pixbuf.rowstride(),
52            has_alpha: pixbuf.has_alpha(),
53            bits_per_sample: pixbuf.bits_per_sample(),
54            n_channels: pixbuf.n_channels(),
55            data: data.to_vec(),
56        }
57    }
58}
59
60#[cfg(feature = "gdk")]
61impl From<&gdk::Texture> for IconData {
62    fn from(texture: &gdk::Texture) -> Self {
63        const BITS_PER_SAMPLE: i32 = 8; // This is the 8 in `MemoryFormat::R8g8b8a8`.
64        const N_CHANNELS: i32 = 4; // vec!['r', 'g', 'b', 'a'].len().
65        const HAS_ALPHA: bool = true; // Did I mention `a8`?
66        let width = texture.width();
67        let height = texture.height();
68
69        let mut downloader = gdk::TextureDownloader::new(texture);
70        downloader.set_format(gdk::MemoryFormat::R8g8b8a8);
71
72        let (data, rowstride) = downloader.download_bytes();
73
74        Self {
75            width,
76            height,
77            rowstride: rowstride as i32,
78            has_alpha: HAS_ALPHA,
79            bits_per_sample: BITS_PER_SAMPLE,
80            n_channels: N_CHANNELS,
81            data: data.to_vec(),
82        }
83    }
84}
85
86/// Create an instance of [`ResultMeta`].
87pub struct ResultMetaBuilder {
88    id: String,
89    name: String,
90    description: Option<String>,
91    clipboard_text: Option<String>,
92    gicon: Option<String>,
93    icon: Option<zbus::zvariant::OwnedValue>,
94    icon_data: Option<IconData>,
95}
96
97impl ResultMetaBuilder {
98    pub fn new(id: ResultID, name: &str) -> Self {
99        Self {
100            id,
101            name: name.to_owned(),
102            gicon: None,
103            description: None,
104            icon: None,
105            icon_data: None,
106            clipboard_text: None,
107        }
108    }
109
110    /// Set a short description of the search result.
111    pub fn description(mut self, description: &str) -> Self {
112        self.description = Some(description.to_owned());
113        self
114    }
115
116    /// Set a text to be copied to the clipboard when the result is activated.
117    pub fn clipboard_text(mut self, clipboard_text: &str) -> Self {
118        self.clipboard_text = Some(clipboard_text.to_owned());
119        self
120    }
121
122    /// Set an icon-name or a URI/path.
123    pub fn gicon(mut self, gicon: &str) -> Self {
124        self.gicon = Some(gicon.to_owned());
125        self
126    }
127
128    /// Set an icon serialized with [`gio::Icon::Serialize`](https://gtk-rs.org/gtk-rs-core/stable/0.14/docs/gio/prelude/trait.IconExt.html#tymethod.serialize).
129    pub fn icon(mut self, icon: zbus::zvariant::OwnedValue) -> Self {
130        self.icon = Some(icon);
131        self
132    }
133
134    /// Set the icon as data. GNOME Shell will re-construct it using GdkPixbuf's API.
135    pub fn icon_data(mut self, icon_data: IconData) -> Self {
136        self.icon_data = Some(icon_data);
137        self
138    }
139
140    /// Build an instance of [`ResultMeta`].
141    pub fn build(self) -> ResultMeta {
142        ResultMeta {
143            id: self.id,
144            name: self.name,
145            gicon: self.gicon,
146            description: self.description,
147            icon: self.icon,
148            icon_data: self.icon_data,
149            clipboard_text: self.clipboard_text,
150        }
151    }
152}
153
154#[cfg(test)]
155mod tests {
156    use zbus::zvariant::Type;
157
158    #[test]
159    fn icon_data_signature() {
160        assert_eq!(super::IconData::SIGNATURE, "(iiibiiay)");
161    }
162}