use std::{fmt, os::fd::AsFd, str::FromStr};
use serde::{Deserialize, Serialize};
use zbus::zvariant::{DeserializeDict, Fd, SerializeDict, Type};
use super::{HandleToken, Request};
use crate::{proxy::Proxy, Error, WindowIdentifier};
#[cfg_attr(feature = "glib", derive(glib::Enum))]
#[cfg_attr(feature = "glib", enum_type(name = "AshpdOrientation"))]
#[derive(Debug, Copy, Clone, Deserialize, Serialize, PartialEq, Eq, Type)]
#[zvariant(signature = "s")]
#[serde(rename_all = "snake_case")]
pub enum Orientation {
Landscape,
Portrait,
ReverseLandscape,
ReversePortrait,
}
impl fmt::Display for Orientation {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Landscape => write!(f, "Landscape"),
Self::Portrait => write!(f, "Portrait"),
Self::ReverseLandscape => write!(f, "Reverse Landscape"),
Self::ReversePortrait => write!(f, "Reverse Portrait"),
}
}
}
impl AsRef<str> for Orientation {
fn as_ref(&self) -> &str {
match self {
Self::Landscape => "Landscape",
Self::Portrait => "Portrait",
Self::ReverseLandscape => "Reverse Landscape",
Self::ReversePortrait => "Reverse Portrait",
}
}
}
impl From<Orientation> for &'static str {
fn from(o: Orientation) -> Self {
match o {
Orientation::Landscape => "Landscape",
Orientation::Portrait => "Portrait",
Orientation::ReverseLandscape => "Reverse Landscape",
Orientation::ReversePortrait => "Reverse Portrait",
}
}
}
impl FromStr for Orientation {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"Landscape" | "landscape" => Ok(Orientation::Landscape),
"Portrait" | "portrait" => Ok(Orientation::Portrait),
"ReverseLandscape" | "reverse_landscape" => Ok(Orientation::ReverseLandscape),
"ReversePortrait" | "reverse_portrait" => Ok(Orientation::ReversePortrait),
_ => Err(Error::ParseError(
"Failed to parse orientation, invalid value",
)),
}
}
}
#[cfg_attr(feature = "glib", derive(glib::Enum))]
#[cfg_attr(feature = "glib", enum_type(name = "AshpdQuality"))]
#[derive(Debug, Clone, Copy, Deserialize, Serialize, PartialEq, Eq, Type)]
#[zvariant(signature = "s")]
#[serde(rename_all = "lowercase")]
pub enum Quality {
Draft,
Low,
Normal,
High,
}
impl fmt::Display for Quality {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Draft => write!(f, "Draft"),
Self::Low => write!(f, "Low"),
Self::Normal => write!(f, "Normal"),
Self::High => write!(f, "High"),
}
}
}
impl AsRef<str> for Quality {
fn as_ref(&self) -> &str {
match self {
Self::Draft => "Draft",
Self::Low => "Low",
Self::Normal => "Normal",
Self::High => "High",
}
}
}
impl From<Quality> for &'static str {
fn from(q: Quality) -> Self {
match q {
Quality::Draft => "Draft",
Quality::Low => "Low",
Quality::Normal => "Normal",
Quality::High => "High",
}
}
}
impl FromStr for Quality {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"Draft" | "draft" => Ok(Quality::Draft),
"Low" | "low" => Ok(Quality::Low),
"Normal" | "normal" => Ok(Quality::Normal),
"High" | "high" => Ok(Quality::High),
_ => Err(Error::ParseError("Failed to parse quality, invalid value")),
}
}
}
#[derive(SerializeDict, DeserializeDict, Type, Debug, Default)]
#[zvariant(signature = "dict")]
pub struct Settings {
pub orientation: Option<Orientation>,
#[zvariant(rename = "paper-format")]
pub paper_format: Option<String>,
#[zvariant(rename = "paper-width")]
pub paper_width: Option<String>,
#[zvariant(rename = "paper-height")]
pub paper_height: Option<String>,
#[zvariant(rename = "n-copies")]
pub n_copies: Option<String>,
#[zvariant(rename = "default-source")]
pub default_source: Option<String>,
pub quality: Option<Quality>,
pub resolution: Option<String>,
#[zvariant(rename = "use-color")]
pub use_color: Option<bool>,
pub duplex: Option<String>,
pub collate: Option<String>,
pub reverse: Option<String>,
#[zvariant(rename = "media-type")]
pub media_type: Option<String>,
pub dither: Option<String>,
pub scale: Option<String>,
#[zvariant(rename = "print-pages")]
pub print_pages: Option<String>,
#[zvariant(rename = "page-ranges")]
pub page_ranges: Option<String>,
#[zvariant(rename = "page-set")]
pub page_set: Option<String>,
pub finishings: Option<String>,
#[zvariant(rename = "number-up")]
pub number_up: Option<String>,
#[zvariant(rename = "number-up-layout")]
pub number_up_layout: Option<String>,
#[zvariant(rename = "output-bin")]
pub output_bin: Option<String>,
#[zvariant(rename = "resolution-x")]
pub resolution_x: Option<String>,
#[zvariant(rename = "resolution-y")]
pub resolution_y: Option<String>,
#[zvariant(rename = "printer-lpi")]
pub print_lpi: Option<String>,
#[zvariant(rename = "output-basename")]
pub output_basename: Option<String>,
#[zvariant(rename = "output-file-format")]
pub output_file_format: Option<String>,
#[zvariant(rename = "output-uri")]
pub output_uri: Option<url::Url>,
}
impl Settings {
#[must_use]
pub fn orientation(mut self, orientation: impl Into<Option<Orientation>>) -> Self {
self.orientation = orientation.into();
self
}
#[must_use]
pub fn paper_format<'a>(mut self, paper_format: impl Into<Option<&'a str>>) -> Self {
self.paper_format = paper_format.into().map(ToOwned::to_owned);
self
}
#[must_use]
pub fn paper_width<'a>(mut self, paper_width: impl Into<Option<&'a str>>) -> Self {
self.paper_width = paper_width.into().map(ToOwned::to_owned);
self
}
#[must_use]
pub fn paper_height<'a>(mut self, paper_height: impl Into<Option<&'a str>>) -> Self {
self.paper_height = paper_height.into().map(ToOwned::to_owned);
self
}
#[must_use]
pub fn n_copies<'a>(mut self, n_copies: impl Into<Option<&'a str>>) -> Self {
self.n_copies = n_copies.into().map(ToOwned::to_owned);
self
}
#[must_use]
pub fn default_source<'a>(mut self, default_source: impl Into<Option<&'a str>>) -> Self {
self.default_source = default_source.into().map(ToOwned::to_owned);
self
}
#[must_use]
pub fn quality(mut self, quality: impl Into<Option<Quality>>) -> Self {
self.quality = quality.into();
self
}
#[must_use]
pub fn resolution<'a>(mut self, resolution: impl Into<Option<&'a str>>) -> Self {
self.resolution = resolution.into().map(ToOwned::to_owned);
self
}
#[must_use]
pub fn use_color(mut self, use_color: impl Into<Option<bool>>) -> Self {
self.use_color = use_color.into();
self
}
#[must_use]
pub fn duplex<'a>(mut self, duplex: impl Into<Option<&'a str>>) -> Self {
self.duplex = duplex.into().map(ToOwned::to_owned);
self
}
#[must_use]
pub fn collate<'a>(mut self, collate: impl Into<Option<&'a str>>) -> Self {
self.collate = collate.into().map(ToOwned::to_owned);
self
}
#[must_use]
pub fn reverse<'a>(mut self, reverse: impl Into<Option<&'a str>>) -> Self {
self.reverse = reverse.into().map(ToOwned::to_owned);
self
}
#[must_use]
pub fn media_type<'a>(mut self, media_type: impl Into<Option<&'a str>>) -> Self {
self.media_type = media_type.into().map(ToOwned::to_owned);
self
}
#[must_use]
pub fn dither<'a>(mut self, dither: impl Into<Option<&'a str>>) -> Self {
self.dither = dither.into().map(ToOwned::to_owned);
self
}
#[must_use]
pub fn scale<'a>(mut self, scale: impl Into<Option<&'a str>>) -> Self {
self.scale = scale.into().map(ToOwned::to_owned);
self
}
#[must_use]
pub fn print_pages<'a>(mut self, print_pages: impl Into<Option<&'a str>>) -> Self {
self.print_pages = print_pages.into().map(ToOwned::to_owned);
self
}
#[must_use]
pub fn page_ranges<'a>(mut self, page_ranges: impl Into<Option<&'a str>>) -> Self {
self.page_ranges = page_ranges.into().map(ToOwned::to_owned);
self
}
#[must_use]
pub fn page_set<'a>(mut self, page_set: impl Into<Option<&'a str>>) -> Self {
self.page_set = page_set.into().map(ToOwned::to_owned);
self
}
#[must_use]
pub fn finishings<'a>(mut self, finishings: impl Into<Option<&'a str>>) -> Self {
self.finishings = finishings.into().map(ToOwned::to_owned);
self
}
#[must_use]
pub fn number_up<'a>(mut self, number_up: impl Into<Option<&'a str>>) -> Self {
self.number_up = number_up.into().map(ToOwned::to_owned);
self
}
#[must_use]
pub fn number_up_layout<'a>(mut self, number_up_layout: impl Into<Option<&'a str>>) -> Self {
self.number_up_layout = number_up_layout.into().map(ToOwned::to_owned);
self
}
#[must_use]
pub fn output_bin<'a>(mut self, output_bin: impl Into<Option<&'a str>>) -> Self {
self.output_bin = output_bin.into().map(ToOwned::to_owned);
self
}
#[must_use]
pub fn resolution_x<'a>(mut self, resolution_x: impl Into<Option<&'a str>>) -> Self {
self.resolution_x = resolution_x.into().map(ToOwned::to_owned);
self
}
#[must_use]
pub fn resolution_y<'a>(mut self, resolution_y: impl Into<Option<&'a str>>) -> Self {
self.resolution_y = resolution_y.into().map(ToOwned::to_owned);
self
}
#[must_use]
pub fn print_lpi<'a>(mut self, print_lpi: impl Into<Option<&'a str>>) -> Self {
self.print_lpi = print_lpi.into().map(ToOwned::to_owned);
self
}
#[must_use]
pub fn output_basename<'a>(mut self, output_basename: impl Into<Option<&'a str>>) -> Self {
self.output_basename = output_basename.into().map(ToOwned::to_owned);
self
}
#[must_use]
pub fn output_file_format<'a>(
mut self,
output_file_format: impl Into<Option<&'a str>>,
) -> Self {
self.output_file_format = output_file_format.into().map(ToOwned::to_owned);
self
}
#[must_use]
pub fn output_uri<'a>(mut self, output_uri: impl Into<Option<&'a url::Url>>) -> Self {
self.output_uri = output_uri.into().map(ToOwned::to_owned);
self
}
}
#[derive(SerializeDict, DeserializeDict, Type, Debug, Default)]
#[zvariant(signature = "dict")]
pub struct PageSetup {
#[zvariant(rename = "PPDName")]
pub ppdname: Option<String>,
pub name: Option<String>,
pub display_name: Option<String>,
pub width: Option<f64>,
pub height: Option<f64>,
pub margin_top: Option<f64>,
pub margin_bottom: Option<f64>,
pub margin_right: Option<f64>,
pub margin_left: Option<f64>,
pub orientation: Option<Orientation>,
}
impl PageSetup {
#[must_use]
pub fn ppdname<'a>(mut self, ppdname: impl Into<Option<&'a str>>) -> Self {
self.ppdname = ppdname.into().map(ToOwned::to_owned);
self
}
#[must_use]
pub fn name<'a>(mut self, name: impl Into<Option<&'a str>>) -> Self {
self.name = name.into().map(ToOwned::to_owned);
self
}
#[must_use]
pub fn display_name<'a>(mut self, display_name: impl Into<Option<&'a str>>) -> Self {
self.display_name = display_name.into().map(ToOwned::to_owned);
self
}
#[must_use]
pub fn orientation(mut self, orientation: impl Into<Option<Orientation>>) -> Self {
self.orientation = orientation.into();
self
}
#[must_use]
pub fn width(mut self, width: impl Into<Option<f64>>) -> Self {
self.width = width.into();
self
}
#[must_use]
pub fn height(mut self, height: impl Into<Option<f64>>) -> Self {
self.height = height.into();
self
}
#[must_use]
pub fn margin_top(mut self, margin_top: impl Into<Option<f64>>) -> Self {
self.margin_top = margin_top.into();
self
}
#[must_use]
pub fn margin_bottom(mut self, margin_bottom: impl Into<Option<f64>>) -> Self {
self.margin_bottom = margin_bottom.into();
self
}
#[must_use]
pub fn margin_right(mut self, margin_right: impl Into<Option<f64>>) -> Self {
self.margin_right = margin_right.into();
self
}
#[must_use]
pub fn margin_left(mut self, margin_left: impl Into<Option<f64>>) -> Self {
self.margin_left = margin_left.into();
self
}
}
#[derive(SerializeDict, Type, Debug, Default)]
#[zvariant(signature = "dict")]
struct PreparePrintOptions {
handle_token: HandleToken,
modal: Option<bool>,
accept_label: Option<String>,
}
impl PreparePrintOptions {
#[must_use]
pub fn modal(mut self, modal: impl Into<Option<bool>>) -> Self {
self.modal = modal.into();
self
}
#[must_use]
pub fn accept_label<'a>(mut self, accept_label: impl Into<Option<&'a str>>) -> Self {
self.accept_label = accept_label.into().map(ToOwned::to_owned);
self
}
}
#[derive(SerializeDict, Type, Debug, Default)]
#[zvariant(signature = "dict")]
struct PrintOptions {
handle_token: HandleToken,
modal: Option<bool>,
token: Option<u32>,
}
impl PrintOptions {
pub fn token(mut self, token: impl Into<Option<u32>>) -> Self {
self.token = token.into();
self
}
pub fn modal(mut self, modal: impl Into<Option<bool>>) -> Self {
self.modal = modal.into();
self
}
}
#[derive(DeserializeDict, SerializeDict, Type, Debug)]
#[zvariant(signature = "dict")]
pub struct PreparePrint {
pub settings: Settings,
#[zvariant(rename = "page-setup")]
pub page_setup: PageSetup,
pub token: u32,
}
#[derive(Debug)]
#[doc(alias = "org.freedesktop.portal.Print")]
pub struct PrintProxy<'a>(Proxy<'a>);
impl<'a> PrintProxy<'a> {
pub async fn new() -> Result<PrintProxy<'a>, Error> {
let proxy = Proxy::new_desktop("org.freedesktop.portal.Print").await?;
Ok(Self(proxy))
}
#[doc(alias = "PreparePrint")]
#[doc(alias = "xdp_portal_prepare_print")]
pub async fn prepare_print(
&self,
identifier: Option<&WindowIdentifier>,
title: &str,
settings: Settings,
page_setup: PageSetup,
accept_label: impl Into<Option<&'a str>>,
modal: bool,
) -> Result<Request<PreparePrint>, Error> {
let options = PreparePrintOptions::default()
.modal(modal)
.accept_label(accept_label);
let identifier = identifier.map(|i| i.to_string()).unwrap_or_default();
self.0
.request(
&options.handle_token,
"PreparePrint",
&(&identifier, title, settings, page_setup, &options),
)
.await
}
#[doc(alias = "Print")]
#[doc(alias = "xdp_portal_print_file")]
pub async fn print(
&self,
identifier: Option<&WindowIdentifier>,
title: &str,
fd: &impl AsFd,
token: Option<u32>,
modal: bool,
) -> Result<Request<()>, Error> {
let options = PrintOptions::default()
.token(token.unwrap_or(0))
.modal(modal);
let identifier = identifier.map(|i| i.to_string()).unwrap_or_default();
self.0
.empty_request(
&options.handle_token,
"Print",
&(&identifier, title, Fd::from(fd), &options),
)
.await
}
}
impl<'a> std::ops::Deref for PrintProxy<'a> {
type Target = zbus::Proxy<'a>;
fn deref(&self) -> &Self::Target {
&self.0
}
}