ashpd/desktop/
wallpaper.rs1use std::{fmt, os::fd::AsFd, str::FromStr};
43
44use serde::{self, Deserialize, Serialize};
45use zbus::zvariant::{Fd, SerializeDict, Type};
46
47use super::Request;
48use crate::{desktop::HandleToken, proxy::Proxy, Error, WindowIdentifier};
49
50#[cfg_attr(feature = "glib", derive(glib::Enum))]
51#[cfg_attr(feature = "glib", enum_type(name = "AshpdSetOn"))]
52#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, Hash, Type)]
53#[zvariant(signature = "s")]
54#[serde(rename_all = "lowercase")]
55pub enum SetOn {
57 Lockscreen,
59 Background,
61 Both,
63}
64
65impl fmt::Display for SetOn {
66 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
67 match self {
68 Self::Lockscreen => write!(f, "Lockscreen"),
69 Self::Background => write!(f, "Background"),
70 Self::Both => write!(f, "Both"),
71 }
72 }
73}
74
75impl AsRef<str> for SetOn {
76 fn as_ref(&self) -> &str {
77 match self {
78 Self::Lockscreen => "Lockscreen",
79 Self::Background => "Background",
80 Self::Both => "Both",
81 }
82 }
83}
84
85impl From<SetOn> for &'static str {
86 fn from(s: SetOn) -> Self {
87 match s {
88 SetOn::Lockscreen => "Lockscreen",
89 SetOn::Background => "Background",
90 SetOn::Both => "Both",
91 }
92 }
93}
94
95impl FromStr for SetOn {
96 type Err = Error;
97
98 fn from_str(s: &str) -> Result<Self, Self::Err> {
99 match s {
100 "Lockscreen" => Ok(SetOn::Lockscreen),
101 "Background" => Ok(SetOn::Background),
102 "Both" => Ok(SetOn::Both),
103 _ => Err(Error::ParseError("Failed to parse SetOn, invalid value")),
104 }
105 }
106}
107
108#[derive(SerializeDict, Type, Debug, Default)]
109#[zvariant(signature = "dict")]
110struct WallpaperOptions {
111 handle_token: HandleToken,
112 #[zvariant(rename = "show-preview")]
113 show_preview: Option<bool>,
114 #[zvariant(rename = "set-on")]
115 set_on: Option<SetOn>,
116}
117
118struct WallpaperProxy<'a>(Proxy<'a>);
119
120impl<'a> WallpaperProxy<'a> {
121 pub async fn new() -> Result<WallpaperProxy<'a>, Error> {
122 let proxy = Proxy::new_desktop("org.freedesktop.portal.Wallpaper").await?;
123 Ok(Self(proxy))
124 }
125
126 pub async fn set_wallpaper_file(
127 &self,
128 identifier: Option<&WindowIdentifier>,
129 file: &impl AsFd,
130 options: WallpaperOptions,
131 ) -> Result<Request<()>, Error> {
132 let identifier = identifier.map(|i| i.to_string()).unwrap_or_default();
133 self.0
134 .empty_request(
135 &options.handle_token,
136 "SetWallpaperFile",
137 &(&identifier, Fd::from(file), &options),
138 )
139 .await
140 }
141
142 pub async fn set_wallpaper_uri(
143 &self,
144 identifier: Option<&WindowIdentifier>,
145 uri: &url::Url,
146 options: WallpaperOptions,
147 ) -> Result<Request<()>, Error> {
148 let identifier = identifier.map(|i| i.to_string()).unwrap_or_default();
149 self.0
150 .empty_request(
151 &options.handle_token,
152 "SetWallpaperURI",
153 &(&identifier, uri, &options),
154 )
155 .await
156 }
157}
158
159impl<'a> std::ops::Deref for WallpaperProxy<'a> {
160 type Target = zbus::Proxy<'a>;
161
162 fn deref(&self) -> &Self::Target {
163 &self.0
164 }
165}
166
167#[derive(Debug, Default)]
168#[doc(alias = "xdp_portal_set_wallpaper")]
169#[doc(alias = "org.freedesktop.portal.Wallpaper")]
170pub struct WallpaperRequest {
174 identifier: Option<WindowIdentifier>,
175 options: WallpaperOptions,
176}
177
178impl WallpaperRequest {
179 #[must_use]
180 pub fn identifier(mut self, identifier: impl Into<Option<WindowIdentifier>>) -> Self {
182 self.identifier = identifier.into();
183 self
184 }
185
186 #[must_use]
190 pub fn show_preview(mut self, show_preview: impl Into<Option<bool>>) -> Self {
191 self.options.show_preview = show_preview.into();
192 self
193 }
194
195 #[must_use]
197 pub fn set_on(mut self, set_on: impl Into<Option<SetOn>>) -> Self {
198 self.options.set_on = set_on.into();
199 self
200 }
201
202 pub async fn build_uri(self, uri: &url::Url) -> Result<Request<()>, Error> {
204 let proxy = WallpaperProxy::new().await?;
205 proxy
206 .set_wallpaper_uri(self.identifier.as_ref(), uri, self.options)
207 .await
208 }
209
210 pub async fn build_file(self, file: &impl AsFd) -> Result<Request<()>, Error> {
212 let proxy = WallpaperProxy::new().await?;
213 proxy
214 .set_wallpaper_file(self.identifier.as_ref(), file, self.options)
215 .await
216 }
217}
218#[cfg(test)]
219mod tests {
220 use super::SetOn;
221
222 #[test]
223 fn serialize_deserialize() {
224 let set_on = SetOn::Both;
225 let string = serde_json::to_string(&set_on).unwrap();
226 assert_eq!(string, "\"both\"");
227
228 let decoded = serde_json::from_str(&string).unwrap();
229 assert_eq!(set_on, decoded);
230 }
231}