1use std::fmt::Debug;
37
38use enumflags2::{BitFlags, bitflags};
39use serde::{Deserialize, Serialize};
40use serde_repr::{Deserialize_repr, Serialize_repr};
41use zbus::zvariant::{
42 Optional, Type,
43 as_value::{self, optional},
44};
45
46use super::{HandleToken, Request};
47use crate::{Error, Uri, WindowIdentifier, desktop::Color, proxy::Proxy};
48
49#[bitflags]
50#[derive(Serialize_repr, Deserialize_repr, PartialEq, Eq, Debug, Copy, Clone, Type)]
51#[repr(u32)]
52pub enum AvailableTargets {
54 Screen = 1,
56 Window = 2,
58 Area = 4,
60 ActiveWindow = 8,
62}
63
64#[derive(Serialize, Deserialize, Type, Debug, Default)]
66#[zvariant(signature = "dict")]
67pub struct ScreenshotOptions {
68 #[serde(with = "as_value", skip_deserializing)]
69 handle_token: HandleToken,
70 #[serde(default, with = "optional", skip_serializing_if = "Option::is_none")]
71 modal: Option<bool>,
72 #[serde(default, with = "optional", skip_serializing_if = "Option::is_none")]
73 interactive: Option<bool>,
74 #[serde(default, with = "optional", skip_serializing)]
75 #[cfg_attr(not(feature = "backend"), allow(dead_code))]
76 permission_store_checked: Option<bool>,
77 #[serde(default, with = "optional", skip_serializing_if = "Option::is_none")]
78 target: Option<AvailableTargets>,
79}
80
81impl ScreenshotOptions {
82 #[must_use]
84 pub fn set_modal(mut self, modal: impl Into<Option<bool>>) -> Self {
85 self.modal = modal.into();
86 self
87 }
88
89 #[cfg(feature = "backend")]
91 pub fn modal(&self) -> Option<bool> {
92 self.modal
93 }
94
95 #[must_use]
97 pub fn set_interactive(mut self, interactive: impl Into<Option<bool>>) -> Self {
98 self.interactive = interactive.into();
99 self
100 }
101
102 #[must_use]
103 pub fn set_target(mut self, targets: impl Into<Option<AvailableTargets>>) -> Self {
105 self.target = targets.into();
106 self
107 }
108
109 #[cfg(feature = "backend")]
111 pub fn interactive(&self) -> Option<bool> {
112 self.interactive
113 }
114
115 #[cfg(feature = "backend")]
117 pub fn target(&self) -> Option<AvailableTargets> {
118 self.target
119 }
120
121 #[cfg(feature = "backend")]
123 pub fn permission_store_checked(&self) -> Option<bool> {
124 self.permission_store_checked
125 }
126}
127
128#[derive(Serialize, Deserialize, Type)]
129#[zvariant(signature = "dict")]
130pub struct Screenshot {
132 #[serde(with = "as_value")]
133 uri: Uri,
134}
135
136impl Screenshot {
137 #[cfg(feature = "backend")]
138 #[cfg_attr(docsrs, doc(cfg(feature = "backend")))]
139 pub fn new(uri: Uri) -> Self {
141 Self { uri }
142 }
143
144 pub fn request() -> ScreenshotRequest {
149 ScreenshotRequest::default()
150 }
151
152 pub fn uri(&self) -> &Uri {
154 &self.uri
155 }
156}
157
158impl Debug for Screenshot {
159 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
160 f.write_str(self.uri.as_str())
161 }
162}
163
164#[derive(Serialize, Deserialize, Type, Debug, Default)]
166#[zvariant(signature = "dict")]
167pub struct ColorOptions {
168 #[serde(with = "as_value", skip_deserializing)]
169 handle_token: HandleToken,
170}
171
172#[derive(Debug)]
174#[doc(alias = "org.freedesktop.portal.Screenshot")]
175pub struct ScreenshotProxy(Proxy<'static>);
176
177impl ScreenshotProxy {
178 pub async fn new() -> Result<Self, Error> {
180 let proxy = Proxy::new_desktop("org.freedesktop.portal.Screenshot").await?;
181 Ok(Self(proxy))
182 }
183
184 pub async fn with_connection(connection: zbus::Connection) -> Result<Self, Error> {
186 let proxy =
187 Proxy::new_desktop_with_connection(connection, "org.freedesktop.portal.Screenshot")
188 .await?;
189 Ok(Self(proxy))
190 }
191
192 pub fn version(&self) -> u32 {
194 self.0.version()
195 }
196
197 #[doc(alias = "PickColor")]
207 #[doc(alias = "xdp_portal_pick_color")]
208 pub async fn pick_color(
209 &self,
210 identifier: Option<&WindowIdentifier>,
211 options: ColorOptions,
212 ) -> Result<Request<Color>, Error> {
213 let identifier = Optional::from(identifier);
214 self.0
215 .request(&options.handle_token, "PickColor", &(identifier, &options))
216 .await
217 }
218
219 #[doc(alias = "Screenshot")]
236 #[doc(alias = "xdp_portal_take_screenshot")]
237 pub async fn screenshot(
238 &self,
239 identifier: Option<&WindowIdentifier>,
240 options: ScreenshotOptions,
241 ) -> Result<Request<Screenshot>, Error> {
242 let identifier = Optional::from(identifier);
243 self.0
244 .request(&options.handle_token, "Screenshot", &(identifier, &options))
245 .await
246 }
247
248 #[doc(alias = "AvailableTargets")]
254 pub async fn available_targets(&self) -> Result<BitFlags<AvailableTargets>, Error> {
255 self.0
256 .property_versioned::<BitFlags<AvailableTargets>>("AvailableTargets", 3)
257 .await
258 }
259}
260
261impl std::ops::Deref for ScreenshotProxy {
262 type Target = zbus::Proxy<'static>;
263
264 fn deref(&self) -> &Self::Target {
265 &self.0
266 }
267}
268
269#[derive(Debug, Default)]
270#[doc(alias = "xdp_portal_pick_color")]
271pub struct ColorRequest {
275 identifier: Option<WindowIdentifier>,
276 options: ColorOptions,
277 connection: Option<zbus::Connection>,
278}
279
280impl ColorRequest {
281 #[must_use]
282 pub fn identifier(mut self, identifier: impl Into<Option<WindowIdentifier>>) -> Self {
284 self.identifier = identifier.into();
285 self
286 }
287
288 #[must_use]
289 pub fn connection(mut self, connection: Option<zbus::Connection>) -> Self {
291 self.connection = connection;
292 self
293 }
294
295 pub async fn send(self) -> Result<Request<Color>, Error> {
297 let proxy = if let Some(connection) = self.connection {
298 ScreenshotProxy::with_connection(connection).await?
299 } else {
300 ScreenshotProxy::new().await?
301 };
302 proxy
303 .pick_color(self.identifier.as_ref(), self.options)
304 .await
305 }
306}
307
308impl Color {
309 pub fn pick() -> ColorRequest {
314 ColorRequest::default()
315 }
316}
317
318#[derive(Debug, Default)]
319#[doc(alias = "xdp_portal_take_screenshot")]
320pub struct ScreenshotRequest {
324 options: ScreenshotOptions,
325 identifier: Option<WindowIdentifier>,
326 connection: Option<zbus::Connection>,
327}
328
329impl ScreenshotRequest {
330 #[must_use]
331 pub fn identifier(mut self, identifier: impl Into<Option<WindowIdentifier>>) -> Self {
333 self.identifier = identifier.into();
334 self
335 }
336
337 #[must_use]
339 pub fn modal(mut self, modal: impl Into<Option<bool>>) -> Self {
340 self.options.modal = modal.into();
341 self
342 }
343
344 #[must_use]
347 pub fn interactive(mut self, interactive: impl Into<Option<bool>>) -> Self {
348 self.options.interactive = interactive.into();
349 self
350 }
351
352 #[must_use]
353 pub fn target(mut self, targets: impl Into<Option<AvailableTargets>>) -> Self {
355 self.options.target = targets.into();
356 self
357 }
358
359 #[must_use]
360 pub fn connection(mut self, connection: Option<zbus::Connection>) -> Self {
362 self.connection = connection;
363 self
364 }
365
366 pub async fn send(self) -> Result<Request<Screenshot>, Error> {
368 let proxy = if let Some(connection) = self.connection {
369 ScreenshotProxy::with_connection(connection).await?
370 } else {
371 ScreenshotProxy::new().await?
372 };
373 proxy
374 .screenshot(self.identifier.as_ref(), self.options)
375 .await
376 }
377}