ashpd/desktop/
print.rs

1//! # Examples
2//!
3//! Print a file
4//!
5//! ```rust,no_run
6//! use std::{fs::File, os::fd::AsFd};
7//!
8//! use ashpd::desktop::print::PrintProxy;
9//!
10//! async fn run() -> ashpd::Result<()> {
11//!     let proxy = PrintProxy::new().await?;
12//!
13//!     let file =
14//!         File::open("/home/bilelmoussaoui/gitlog.pdf").expect("file to print was not found");
15//!     let pre_print = proxy
16//!         .prepare_print(
17//!             None,
18//!             "prepare print",
19//!             Default::default(),
20//!             Default::default(),
21//!             None,
22//!             true,
23//!         )
24//!         .await?
25//!         .response()?;
26//!     proxy
27//!         .print(None, "test", &file.as_fd(), Some(pre_print.token), true)
28//!         .await?;
29//!
30//!     Ok(())
31//! }
32//! ```
33
34use std::{fmt, os::fd::AsFd, str::FromStr};
35
36use serde::{Deserialize, Serialize};
37use zbus::zvariant::{DeserializeDict, Fd, SerializeDict, Type};
38
39use super::{HandleToken, Request};
40use crate::{proxy::Proxy, Error, WindowIdentifier};
41
42#[cfg_attr(feature = "glib", derive(glib::Enum))]
43#[cfg_attr(feature = "glib", enum_type(name = "AshpdOrientation"))]
44#[derive(Debug, Copy, Clone, Deserialize, Serialize, PartialEq, Eq, Type)]
45#[zvariant(signature = "s")]
46#[serde(rename_all = "snake_case")]
47/// The page orientation.
48pub enum Orientation {
49    /// Landscape.
50    Landscape,
51    /// Portrait.
52    Portrait,
53    /// Reverse landscape.
54    ReverseLandscape,
55    /// Reverse portrait.
56    ReversePortrait,
57}
58
59impl fmt::Display for Orientation {
60    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
61        match self {
62            Self::Landscape => write!(f, "Landscape"),
63            Self::Portrait => write!(f, "Portrait"),
64            Self::ReverseLandscape => write!(f, "Reverse Landscape"),
65            Self::ReversePortrait => write!(f, "Reverse Portrait"),
66        }
67    }
68}
69
70impl AsRef<str> for Orientation {
71    fn as_ref(&self) -> &str {
72        match self {
73            Self::Landscape => "Landscape",
74            Self::Portrait => "Portrait",
75            Self::ReverseLandscape => "Reverse Landscape",
76            Self::ReversePortrait => "Reverse Portrait",
77        }
78    }
79}
80
81impl From<Orientation> for &'static str {
82    fn from(o: Orientation) -> Self {
83        match o {
84            Orientation::Landscape => "Landscape",
85            Orientation::Portrait => "Portrait",
86            Orientation::ReverseLandscape => "Reverse Landscape",
87            Orientation::ReversePortrait => "Reverse Portrait",
88        }
89    }
90}
91
92impl FromStr for Orientation {
93    type Err = Error;
94
95    fn from_str(s: &str) -> Result<Self, Self::Err> {
96        match s {
97            "Landscape" | "landscape" => Ok(Orientation::Landscape),
98            "Portrait" | "portrait" => Ok(Orientation::Portrait),
99            "ReverseLandscape" | "reverse_landscape" => Ok(Orientation::ReverseLandscape),
100            "ReversePortrait" | "reverse_portrait" => Ok(Orientation::ReversePortrait),
101            _ => Err(Error::ParseError(
102                "Failed to parse orientation, invalid value",
103            )),
104        }
105    }
106}
107
108#[cfg_attr(feature = "glib", derive(glib::Enum))]
109#[cfg_attr(feature = "glib", enum_type(name = "AshpdQuality"))]
110#[derive(Debug, Clone, Copy, Deserialize, Serialize, PartialEq, Eq, Type)]
111#[zvariant(signature = "s")]
112#[serde(rename_all = "lowercase")]
113/// The print quality.
114pub enum Quality {
115    /// Draft quality.
116    Draft,
117    /// Low quality.
118    Low,
119    /// Normal quality.
120    Normal,
121    /// High quality.
122    High,
123}
124
125impl fmt::Display for Quality {
126    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
127        match self {
128            Self::Draft => write!(f, "Draft"),
129            Self::Low => write!(f, "Low"),
130            Self::Normal => write!(f, "Normal"),
131            Self::High => write!(f, "High"),
132        }
133    }
134}
135
136impl AsRef<str> for Quality {
137    fn as_ref(&self) -> &str {
138        match self {
139            Self::Draft => "Draft",
140            Self::Low => "Low",
141            Self::Normal => "Normal",
142            Self::High => "High",
143        }
144    }
145}
146
147impl From<Quality> for &'static str {
148    fn from(q: Quality) -> Self {
149        match q {
150            Quality::Draft => "Draft",
151            Quality::Low => "Low",
152            Quality::Normal => "Normal",
153            Quality::High => "High",
154        }
155    }
156}
157
158impl FromStr for Quality {
159    type Err = Error;
160
161    fn from_str(s: &str) -> Result<Self, Self::Err> {
162        match s {
163            "Draft" | "draft" => Ok(Quality::Draft),
164            "Low" | "low" => Ok(Quality::Low),
165            "Normal" | "normal" => Ok(Quality::Normal),
166            "High" | "high" => Ok(Quality::High),
167            _ => Err(Error::ParseError("Failed to parse quality, invalid value")),
168        }
169    }
170}
171
172#[derive(SerializeDict, DeserializeDict, Type, Debug, Default)]
173/// Print settings to set in the print dialog.
174#[zvariant(signature = "dict")]
175pub struct Settings {
176    /// One of landscape, portrait, reverse_landscape or reverse_portrait.
177    pub orientation: Option<Orientation>,
178    /// A paper name according to [PWG 5101.1-2002](ftp://ftp.pwg.org/pub/pwg/candidates/cs-pwgmsn10-20020226-5101.1.pdf)
179    #[zvariant(rename = "paper-format")]
180    pub paper_format: Option<String>,
181    /// Paper width, in millimeters.
182    #[zvariant(rename = "paper-width")]
183    pub paper_width: Option<String>,
184    /// Paper height, in millimeters.
185    #[zvariant(rename = "paper-height")]
186    pub paper_height: Option<String>,
187    /// The number of copies to print.
188    #[zvariant(rename = "n-copies")]
189    pub n_copies: Option<String>,
190    /// The default paper source.
191    #[zvariant(rename = "default-source")]
192    pub default_source: Option<String>,
193    /// Print quality.
194    pub quality: Option<Quality>,
195    /// The resolution, sets both resolution-x & resolution-y
196    pub resolution: Option<String>,
197    /// Whether to use color.
198    #[zvariant(rename = "use-color")]
199    pub use_color: Option<String>,
200    /// Duplex printing mode, one of simplex, horizontal or vertical.
201    pub duplex: Option<String>,
202    /// Whether to collate copies.
203    pub collate: Option<String>,
204    /// Whether to reverse the order of printed pages.
205    pub reverse: Option<String>,
206    /// A media type according to [PWG 5101.1-2002](ftp://ftp.pwg.org/pub/pwg/candidates/cs-pwgmsn10-20020226-5101.1.pdf)
207    #[zvariant(rename = "media-type")]
208    pub media_type: Option<String>,
209    /// The dithering to use, one of fine, none, coarse, lineart, grayscale or
210    /// error-diffusion.
211    pub dither: Option<String>,
212    /// The scale in percent
213    pub scale: Option<String>,
214    /// What pages to print, one of all, selection, current or ranges.
215    #[zvariant(rename = "print-pages")]
216    pub print_pages: Option<String>,
217    /// A list of page ranges, formatted like this: 0-2,4,9-11.
218    #[zvariant(rename = "page-ranges")]
219    pub page_ranges: Option<String>,
220    /// What pages to print, one of all, even or odd.
221    #[zvariant(rename = "page-set")]
222    pub page_set: Option<String>,
223    /// The finishings.
224    pub finishings: Option<String>,
225    /// The number of pages per sheet.
226    #[zvariant(rename = "number-up")]
227    pub number_up: Option<String>,
228    /// One of lrtb, lrbt, rltb, rlbt, tblr, tbrl, btlr, btrl.
229    #[zvariant(rename = "number-up-layout")]
230    pub number_up_layout: Option<String>,
231    #[zvariant(rename = "output-bin")]
232    /// The output bin.
233    pub output_bin: Option<String>,
234    /// The horizontal resolution in dpi.
235    #[zvariant(rename = "resolution-x")]
236    pub resolution_x: Option<String>,
237    /// The vertical resolution in dpi.
238    #[zvariant(rename = "resolution-y")]
239    pub resolution_y: Option<String>,
240    /// The resolution in lpi (lines per inch).
241    #[zvariant(rename = "printer-lpi")]
242    pub print_lpi: Option<String>,
243    /// Basename to use for print-to-file.
244    #[zvariant(rename = "output-basename")]
245    pub output_basename: Option<String>,
246    /// Format to use for print-to-file, one of PDF, PS, SVG
247    #[zvariant(rename = "output-file-format")]
248    pub output_file_format: Option<String>,
249    /// The uri used for print-to file.
250    #[zvariant(rename = "output-uri")]
251    pub output_uri: Option<url::Url>,
252}
253
254impl Settings {
255    /// Sets the orientation.
256    #[must_use]
257    pub fn orientation(mut self, orientation: impl Into<Option<Orientation>>) -> Self {
258        self.orientation = orientation.into();
259        self
260    }
261
262    /// Sets the paper name.
263    #[must_use]
264    pub fn paper_format<'a>(mut self, paper_format: impl Into<Option<&'a str>>) -> Self {
265        self.paper_format = paper_format.into().map(ToOwned::to_owned);
266        self
267    }
268
269    /// Sets the paper width.
270    #[must_use]
271    pub fn paper_width<'a>(mut self, paper_width: impl Into<Option<&'a str>>) -> Self {
272        self.paper_width = paper_width.into().map(ToOwned::to_owned);
273        self
274    }
275
276    /// Sets the paper height.
277    #[must_use]
278    pub fn paper_height<'a>(mut self, paper_height: impl Into<Option<&'a str>>) -> Self {
279        self.paper_height = paper_height.into().map(ToOwned::to_owned);
280        self
281    }
282
283    /// Sets the number of copies to print.
284    #[must_use]
285    pub fn n_copies<'a>(mut self, n_copies: impl Into<Option<&'a str>>) -> Self {
286        self.n_copies = n_copies.into().map(ToOwned::to_owned);
287        self
288    }
289
290    /// Sets the default paper source.
291    #[must_use]
292    pub fn default_source<'a>(mut self, default_source: impl Into<Option<&'a str>>) -> Self {
293        self.default_source = default_source.into().map(ToOwned::to_owned);
294        self
295    }
296
297    /// Sets the print quality.
298    #[must_use]
299    pub fn quality(mut self, quality: impl Into<Option<Quality>>) -> Self {
300        self.quality = quality.into();
301        self
302    }
303
304    /// Sets the resolution, both resolution-x & resolution-y.
305    #[must_use]
306    pub fn resolution<'a>(mut self, resolution: impl Into<Option<&'a str>>) -> Self {
307        self.resolution = resolution.into().map(ToOwned::to_owned);
308        self
309    }
310
311    /// Sets whether to use color.
312    #[must_use]
313    pub fn use_color(mut self, use_color: impl Into<Option<bool>>) -> Self {
314        let use_color = use_color.into().unwrap_or_default();
315        if use_color {
316            self.use_color = Some("yes".to_owned());
317        } else {
318            self.use_color = Some("no".to_owned())
319        };
320        self
321    }
322
323    /// Sets the duplex printing mode.
324    #[must_use]
325    pub fn duplex<'a>(mut self, duplex: impl Into<Option<&'a str>>) -> Self {
326        self.duplex = duplex.into().map(ToOwned::to_owned);
327        self
328    }
329
330    /// Whether to collate copies.
331    #[must_use]
332    pub fn collate(mut self, collate: impl Into<Option<bool>>) -> Self {
333        let collate = collate.into().unwrap_or_default();
334        if collate {
335            self.collate = Some("yes".to_owned());
336        } else {
337            self.collate = Some("no".to_owned())
338        };
339        self
340    }
341
342    /// Sets whether to reverse the order of the printed pages.
343    #[must_use]
344    pub fn reverse(mut self, reverse: impl Into<Option<bool>>) -> Self {
345        let reverse = reverse.into().unwrap_or_default();
346        if reverse {
347            self.reverse = Some("yes".to_owned());
348        } else {
349            self.reverse = Some("no".to_owned())
350        };
351        self
352    }
353
354    /// Sets the media type.
355    #[must_use]
356    pub fn media_type<'a>(mut self, media_type: impl Into<Option<&'a str>>) -> Self {
357        self.media_type = media_type.into().map(ToOwned::to_owned);
358        self
359    }
360
361    /// Sets the dithering to use.
362    #[must_use]
363    pub fn dither<'a>(mut self, dither: impl Into<Option<&'a str>>) -> Self {
364        self.dither = dither.into().map(ToOwned::to_owned);
365        self
366    }
367
368    /// Sets the page scale in percent.
369    #[must_use]
370    pub fn scale<'a>(mut self, scale: impl Into<Option<&'a str>>) -> Self {
371        self.scale = scale.into().map(ToOwned::to_owned);
372        self
373    }
374
375    /// Sets what pages to print, one of all, selection, current or ranges.
376    #[must_use]
377    pub fn print_pages<'a>(mut self, print_pages: impl Into<Option<&'a str>>) -> Self {
378        self.print_pages = print_pages.into().map(ToOwned::to_owned);
379        self
380    }
381
382    /// Sets a list of page ranges, formatted like this: 0-2,4,9-11.
383    #[must_use]
384    pub fn page_ranges<'a>(mut self, page_ranges: impl Into<Option<&'a str>>) -> Self {
385        self.page_ranges = page_ranges.into().map(ToOwned::to_owned);
386        self
387    }
388
389    /// Sets what pages to print, one of all, even or odd.
390    #[must_use]
391    pub fn page_set<'a>(mut self, page_set: impl Into<Option<&'a str>>) -> Self {
392        self.page_set = page_set.into().map(ToOwned::to_owned);
393        self
394    }
395
396    /// Sets the finishings.
397    #[must_use]
398    pub fn finishings<'a>(mut self, finishings: impl Into<Option<&'a str>>) -> Self {
399        self.finishings = finishings.into().map(ToOwned::to_owned);
400        self
401    }
402
403    /// Sets the number of pages per sheet.
404    #[must_use]
405    pub fn number_up<'a>(mut self, number_up: impl Into<Option<&'a str>>) -> Self {
406        self.number_up = number_up.into().map(ToOwned::to_owned);
407        self
408    }
409
410    /// Sets the number up layout, one of lrtb, lrbt, rltb, rlbt, tblr, tbrl,
411    /// btlr, btrl.
412    #[must_use]
413    pub fn number_up_layout<'a>(mut self, number_up_layout: impl Into<Option<&'a str>>) -> Self {
414        self.number_up_layout = number_up_layout.into().map(ToOwned::to_owned);
415        self
416    }
417
418    /// Sets the output bin
419    #[must_use]
420    pub fn output_bin<'a>(mut self, output_bin: impl Into<Option<&'a str>>) -> Self {
421        self.output_bin = output_bin.into().map(ToOwned::to_owned);
422        self
423    }
424
425    /// Sets the horizontal resolution in dpi.
426    #[must_use]
427    pub fn resolution_x<'a>(mut self, resolution_x: impl Into<Option<&'a str>>) -> Self {
428        self.resolution_x = resolution_x.into().map(ToOwned::to_owned);
429        self
430    }
431
432    /// Sets the vertical resolution in dpi.
433    #[must_use]
434    pub fn resolution_y<'a>(mut self, resolution_y: impl Into<Option<&'a str>>) -> Self {
435        self.resolution_y = resolution_y.into().map(ToOwned::to_owned);
436        self
437    }
438
439    /// Sets the resolution in lines per inch.
440    #[must_use]
441    pub fn print_lpi<'a>(mut self, print_lpi: impl Into<Option<&'a str>>) -> Self {
442        self.print_lpi = print_lpi.into().map(ToOwned::to_owned);
443        self
444    }
445
446    /// Sets the print-to-file base name.
447    #[must_use]
448    pub fn output_basename<'a>(mut self, output_basename: impl Into<Option<&'a str>>) -> Self {
449        self.output_basename = output_basename.into().map(ToOwned::to_owned);
450        self
451    }
452
453    /// Sets the print-to-file format, one of PS, PDF, SVG.
454    #[must_use]
455    pub fn output_file_format<'a>(
456        mut self,
457        output_file_format: impl Into<Option<&'a str>>,
458    ) -> Self {
459        self.output_file_format = output_file_format.into().map(ToOwned::to_owned);
460        self
461    }
462
463    /// Sets the print-to-file output uri.
464    #[must_use]
465    pub fn output_uri<'a>(mut self, output_uri: impl Into<Option<&'a url::Url>>) -> Self {
466        self.output_uri = output_uri.into().map(ToOwned::to_owned);
467        self
468    }
469}
470
471#[derive(SerializeDict, DeserializeDict, Type, Debug, Default)]
472/// Setup the printed pages.
473#[zvariant(signature = "dict")]
474pub struct PageSetup {
475    /// the PPD name. It's the name to select a given driver.
476    #[zvariant(rename = "PPDName")]
477    pub ppdname: Option<String>,
478    /// The name of the page setup.
479    #[zvariant(rename = "Name")]
480    pub name: Option<String>,
481    /// The user-visible name of the page setup.
482    #[zvariant(rename = "DisplayName")]
483    pub display_name: Option<String>,
484    /// Paper width in millimeters.
485    #[zvariant(rename = "Width")]
486    pub width: Option<f64>,
487    /// Paper height in millimeters.
488    #[zvariant(rename = "Height")]
489    pub height: Option<f64>,
490    /// Top margin in millimeters.
491    #[zvariant(rename = "MarginTop")]
492    pub margin_top: Option<f64>,
493    /// Bottom margin in millimeters.
494    #[zvariant(rename = "MarginBottom")]
495    pub margin_bottom: Option<f64>,
496    /// Right margin in millimeters.
497    #[zvariant(rename = "MarginRight")]
498    pub margin_right: Option<f64>,
499    /// Left margin in millimeters.
500    #[zvariant(rename = "MarginLeft")]
501    pub margin_left: Option<f64>,
502    /// The page orientation.
503    #[zvariant(rename = "Orientation")]
504    pub orientation: Option<Orientation>,
505}
506
507impl PageSetup {
508    /// Sets the ppdname.
509    #[must_use]
510    pub fn ppdname<'a>(mut self, ppdname: impl Into<Option<&'a str>>) -> Self {
511        self.ppdname = ppdname.into().map(ToOwned::to_owned);
512        self
513    }
514
515    /// Sets the name of the page setup.
516    #[must_use]
517    pub fn name<'a>(mut self, name: impl Into<Option<&'a str>>) -> Self {
518        self.name = name.into().map(ToOwned::to_owned);
519        self
520    }
521
522    /// Sets the user visible name of the page setup.
523    #[must_use]
524    pub fn display_name<'a>(mut self, display_name: impl Into<Option<&'a str>>) -> Self {
525        self.display_name = display_name.into().map(ToOwned::to_owned);
526        self
527    }
528
529    /// Sets the orientation.
530    #[must_use]
531    pub fn orientation(mut self, orientation: impl Into<Option<Orientation>>) -> Self {
532        self.orientation = orientation.into();
533        self
534    }
535
536    /// Sets the page width.
537    #[must_use]
538    pub fn width(mut self, width: impl Into<Option<f64>>) -> Self {
539        self.width = width.into();
540        self
541    }
542
543    /// Sets the page height.
544    #[must_use]
545    pub fn height(mut self, height: impl Into<Option<f64>>) -> Self {
546        self.height = height.into();
547        self
548    }
549
550    /// Sets the page top margin.
551    #[must_use]
552    pub fn margin_top(mut self, margin_top: impl Into<Option<f64>>) -> Self {
553        self.margin_top = margin_top.into();
554        self
555    }
556
557    /// Sets the page bottom margin.
558    #[must_use]
559    pub fn margin_bottom(mut self, margin_bottom: impl Into<Option<f64>>) -> Self {
560        self.margin_bottom = margin_bottom.into();
561        self
562    }
563
564    /// Sets the page right margin.
565    #[must_use]
566    pub fn margin_right(mut self, margin_right: impl Into<Option<f64>>) -> Self {
567        self.margin_right = margin_right.into();
568        self
569    }
570
571    /// Sets the page margin left.
572    #[must_use]
573    pub fn margin_left(mut self, margin_left: impl Into<Option<f64>>) -> Self {
574        self.margin_left = margin_left.into();
575        self
576    }
577}
578
579#[derive(SerializeDict, Type, Debug, Default)]
580/// Specified options for a [`PrintProxy::prepare_print`] request.
581#[zvariant(signature = "dict")]
582struct PreparePrintOptions {
583    /// A string that will be used as the last element of the handle.
584    handle_token: HandleToken,
585    /// Whether to make the dialog modal.
586    modal: Option<bool>,
587    /// Label for the accept button. Mnemonic underlines are allowed.
588    accept_label: Option<String>,
589}
590
591impl PreparePrintOptions {
592    /// Sets whether the dialog should be a modal.
593    #[must_use]
594    pub fn modal(mut self, modal: impl Into<Option<bool>>) -> Self {
595        self.modal = modal.into();
596        self
597    }
598
599    /// Label for the accept button. Mnemonic underlines are allowed.
600    #[must_use]
601    pub fn accept_label<'a>(mut self, accept_label: impl Into<Option<&'a str>>) -> Self {
602        self.accept_label = accept_label.into().map(ToOwned::to_owned);
603        self
604    }
605}
606
607#[derive(SerializeDict, Type, Debug, Default)]
608/// Specified options for a [`PrintProxy::print`] request.
609#[zvariant(signature = "dict")]
610struct PrintOptions {
611    /// A string that will be used as the last element of the handle.
612    handle_token: HandleToken,
613    /// Whether to make the dialog modal.
614    modal: Option<bool>,
615    /// Token that was returned by a previous [`PrintProxy::prepare_print`]
616    /// call.
617    token: Option<u32>,
618}
619
620impl PrintOptions {
621    /// A token retrieved from [`PrintProxy::prepare_print`].
622    pub fn token(mut self, token: impl Into<Option<u32>>) -> Self {
623        self.token = token.into();
624        self
625    }
626
627    /// Sets whether the dialog should be a modal.
628    pub fn modal(mut self, modal: impl Into<Option<bool>>) -> Self {
629        self.modal = modal.into();
630        self
631    }
632}
633
634#[derive(DeserializeDict, SerializeDict, Type, Debug)]
635/// A response to a [`PrintProxy::prepare_print`] request.
636#[zvariant(signature = "dict")]
637pub struct PreparePrint {
638    /// The printing settings.
639    pub settings: Settings,
640    #[zvariant(rename = "page-setup")]
641    /// The printed pages setup.
642    pub page_setup: PageSetup,
643    /// A token to pass to the print request.
644    pub token: u32,
645}
646
647/// The interface lets sandboxed applications print.
648///
649/// Wrapper of the DBus interface: [`org.freedesktop.portal.Print`](https://flatpak.github.io/xdg-desktop-portal/docs/doc-org.freedesktop.portal.Print.html).
650#[derive(Debug)]
651#[doc(alias = "org.freedesktop.portal.Print")]
652pub struct PrintProxy<'a>(Proxy<'a>);
653
654impl<'a> PrintProxy<'a> {
655    /// Create a new instance of [`PrintProxy`].
656    pub async fn new() -> Result<PrintProxy<'a>, Error> {
657        let proxy = Proxy::new_desktop("org.freedesktop.portal.Print").await?;
658        Ok(Self(proxy))
659    }
660
661    // TODO accept_label: Added in version 2 of the interface.
662    /// Presents a print dialog to the user and returns print settings and page
663    /// setup.
664    ///
665    /// # Arguments
666    ///
667    /// * `identifier` - Identifier for the application window.
668    /// * `title` - Title for the print dialog.
669    /// * `settings` - [`Settings`].
670    /// * `page_setup` - [`PageSetup`].
671    /// * `modal` - Whether the dialog should be a modal.
672    /// * `accept_label` - Label for the accept button. Mnemonic underlines are
673    ///   allowed.
674    ///
675    /// # Specifications
676    ///
677    /// See also [`PreparePrint`](https://flatpak.github.io/xdg-desktop-portal/docs/doc-org.freedesktop.portal.Print.html#org-freedesktop-portal-print-prepareprint).
678    #[doc(alias = "PreparePrint")]
679    #[doc(alias = "xdp_portal_prepare_print")]
680    pub async fn prepare_print(
681        &self,
682        identifier: Option<&WindowIdentifier>,
683        title: &str,
684        settings: Settings,
685        page_setup: PageSetup,
686        accept_label: impl Into<Option<&'a str>>,
687        modal: bool,
688    ) -> Result<Request<PreparePrint>, Error> {
689        let options = PreparePrintOptions::default()
690            .modal(modal)
691            .accept_label(accept_label);
692        let identifier = identifier.map(|i| i.to_string()).unwrap_or_default();
693        self.0
694            .request(
695                &options.handle_token,
696                "PreparePrint",
697                &(&identifier, title, settings, page_setup, &options),
698            )
699            .await
700    }
701
702    /// Asks to print a file.
703    /// The file must be passed in the form of a file descriptor open for
704    /// reading. This ensures that sandboxed applications only print files
705    /// that they have access to.
706    ///
707    /// # Arguments
708    ///
709    /// * `identifier` - The application window identifier.
710    /// * `title` - The title for the print dialog.
711    /// * `fd` - File descriptor for reading the content to print.
712    /// * `token` - A token returned by a call to
713    ///   [`prepare_print()`][`PrintProxy::prepare_print`].
714    /// * `modal` - Whether the dialog should be a modal.
715    ///
716    /// # Specifications
717    ///
718    /// See also [`Print`](https://flatpak.github.io/xdg-desktop-portal/docs/doc-org.freedesktop.portal.Print.html#org-freedesktop-portal-print-print).
719    #[doc(alias = "Print")]
720    #[doc(alias = "xdp_portal_print_file")]
721    pub async fn print(
722        &self,
723        identifier: Option<&WindowIdentifier>,
724        title: &str,
725        fd: &impl AsFd,
726        token: Option<u32>,
727        modal: bool,
728    ) -> Result<Request<()>, Error> {
729        let options = PrintOptions::default()
730            .token(token.unwrap_or(0))
731            .modal(modal);
732        let identifier = identifier.map(|i| i.to_string()).unwrap_or_default();
733
734        self.0
735            .empty_request(
736                &options.handle_token,
737                "Print",
738                &(&identifier, title, Fd::from(fd), &options),
739            )
740            .await
741    }
742}
743
744impl<'a> std::ops::Deref for PrintProxy<'a> {
745    type Target = zbus::Proxy<'a>;
746
747    fn deref(&self) -> &Self::Target {
748        &self.0
749    }
750}