use std::os::unix::prelude::AsRawFd;
use std::{fmt, str::FromStr};
use serde::{Deserialize, Serialize, Serializer};
use zbus::zvariant::{DeserializeDict, Fd, SerializeDict, Signature, Type};
use super::{HandleToken, DESTINATION, PATH};
use crate::{
helpers::{call_basic_response_method, call_request_method},
Error, WindowIdentifier,
};
#[derive(Debug, Clone, Deserialize, PartialEq, Eq)]
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".to_string(),
)),
}
}
}
impl Serialize for Orientation {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match self {
Self::Landscape => serializer.serialize_str("landscape"),
Self::Portrait => serializer.serialize_str("portrait"),
Self::ReverseLandscape => serializer.serialize_str("reverse_landscape"),
Self::ReversePortrait => serializer.serialize_str("reverse_portrait"),
}
}
}
impl Type for Orientation {
fn signature() -> Signature<'static> {
String::signature()
}
}
#[derive(Debug, Clone, Deserialize, PartialEq, Eq)]
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".to_string(),
)),
}
}
}
impl Serialize for Quality {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(&self.to_string().to_lowercase())
}
}
impl Type for Quality {
fn signature() -> Signature<'static> {
String::signature()
}
}
#[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<String>,
}
impl Settings {
#[must_use]
pub fn orientation(mut self, orientation: Orientation) -> Self {
self.orientation = Some(orientation);
self
}
#[must_use]
pub fn paper_format(mut self, paper_format: &str) -> Self {
self.paper_format = Some(paper_format.to_string());
self
}
#[must_use]
pub fn paper_width(mut self, paper_width: &str) -> Self {
self.paper_width = Some(paper_width.to_string());
self
}
#[must_use]
pub fn paper_height(mut self, paper_height: &str) -> Self {
self.paper_height = Some(paper_height.to_string());
self
}
#[must_use]
pub fn n_copies(mut self, n_copies: &str) -> Self {
self.n_copies = Some(n_copies.to_string());
self
}
#[must_use]
pub fn default_source(mut self, default_source: &str) -> Self {
self.default_source = Some(default_source.to_string());
self
}
#[must_use]
pub fn quality(mut self, quality: Quality) -> Self {
self.quality = Some(quality);
self
}
#[must_use]
pub fn resolution(mut self, resolution: &str) -> Self {
self.resolution = Some(resolution.to_string());
self
}
#[must_use]
pub fn use_color(mut self, use_color: bool) -> Self {
self.use_color = Some(use_color);
self
}
#[must_use]
pub fn duplex(mut self, duplex: &str) -> Self {
self.duplex = Some(duplex.to_string());
self
}
#[must_use]
pub fn collate(mut self, collate: &str) -> Self {
self.collate = Some(collate.to_string());
self
}
#[must_use]
pub fn reverse(mut self, reverse: &str) -> Self {
self.reverse = Some(reverse.to_string());
self
}
#[must_use]
pub fn media_type(mut self, media_type: &str) -> Self {
self.media_type = Some(media_type.to_string());
self
}
#[must_use]
pub fn dither(mut self, dither: &str) -> Self {
self.dither = Some(dither.to_string());
self
}
#[must_use]
pub fn scale(mut self, scale: &str) -> Self {
self.scale = Some(scale.to_string());
self
}
#[must_use]
pub fn print_pages(mut self, print_pages: &str) -> Self {
self.print_pages = Some(print_pages.to_string());
self
}
#[must_use]
pub fn page_ranges(mut self, page_ranges: &str) -> Self {
self.page_ranges = Some(page_ranges.to_string());
self
}
#[must_use]
pub fn page_set(mut self, page_set: &str) -> Self {
self.page_set = Some(page_set.to_string());
self
}
#[must_use]
pub fn finishings(mut self, finishings: &str) -> Self {
self.finishings = Some(finishings.to_string());
self
}
#[must_use]
pub fn number_up(mut self, number_up: &str) -> Self {
self.number_up = Some(number_up.to_string());
self
}
#[must_use]
pub fn number_up_layout(mut self, number_up_layout: &str) -> Self {
self.number_up_layout = Some(number_up_layout.to_string());
self
}
#[must_use]
pub fn output_bin(mut self, output_bin: &str) -> Self {
self.output_bin = Some(output_bin.to_string());
self
}
#[must_use]
pub fn resolution_x(mut self, resolution_x: &str) -> Self {
self.resolution_x = Some(resolution_x.to_string());
self
}
#[must_use]
pub fn resolution_y(mut self, resolution_y: &str) -> Self {
self.resolution_y = Some(resolution_y.to_string());
self
}
#[must_use]
pub fn print_lpi(mut self, print_lpi: &str) -> Self {
self.print_lpi = Some(print_lpi.to_string());
self
}
#[must_use]
pub fn output_basename(mut self, output_basename: &str) -> Self {
self.output_basename = Some(output_basename.to_string());
self
}
#[must_use]
pub fn output_file_format(mut self, output_file_format: &str) -> Self {
self.output_file_format = Some(output_file_format.to_string());
self
}
#[must_use]
pub fn output_uri(mut self, output_uri: &str) -> Self {
self.output_uri = Some(output_uri.to_string());
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(mut self, ppdname: &str) -> Self {
self.ppdname = Some(ppdname.to_string());
self
}
#[must_use]
pub fn name(mut self, name: &str) -> Self {
self.name = Some(name.to_string());
self
}
#[must_use]
pub fn display_name(mut self, display_name: &str) -> Self {
self.display_name = Some(display_name.to_string());
self
}
#[must_use]
pub fn orientation(mut self, orientation: Orientation) -> Self {
self.orientation = Some(orientation);
self
}
#[must_use]
pub fn width(mut self, width: f64) -> Self {
self.width = Some(width);
self
}
#[must_use]
pub fn height(mut self, height: f64) -> Self {
self.height = Some(height);
self
}
#[must_use]
pub fn margin_top(mut self, margin_top: f64) -> Self {
self.margin_top = Some(margin_top);
self
}
#[must_use]
pub fn margin_bottom(mut self, margin_bottom: f64) -> Self {
self.margin_bottom = Some(margin_bottom);
self
}
#[must_use]
pub fn margin_right(mut self, margin_right: f64) -> Self {
self.margin_right = Some(margin_right);
self
}
#[must_use]
pub fn margin_left(mut self, margin_left: f64) -> Self {
self.margin_left = Some(margin_left);
self
}
}
#[derive(SerializeDict, DeserializeDict, Type, Debug, Default)]
#[zvariant(signature = "dict")]
struct PreparePrintOptions {
handle_token: HandleToken,
modal: Option<bool>,
}
impl PreparePrintOptions {
pub fn modal(mut self, modal: bool) -> Self {
self.modal = Some(modal);
self
}
}
#[derive(SerializeDict, DeserializeDict, 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: u32) -> Self {
self.token = Some(token);
self
}
pub fn modal(mut self, modal: bool) -> Self {
self.modal = Some(modal);
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>(zbus::Proxy<'a>);
impl<'a> PrintProxy<'a> {
pub async fn new(connection: &zbus::Connection) -> Result<PrintProxy<'a>, Error> {
let proxy = zbus::ProxyBuilder::new_bare(connection)
.interface("org.freedesktop.portal.Print")?
.path(PATH)?
.destination(DESTINATION)?
.build()
.await?;
Ok(Self(proxy))
}
pub fn inner(&self) -> &zbus::Proxy<'_> {
&self.0
}
#[doc(alias = "PreparePrint")]
#[doc(alias = "xdp_portal_prepare_print")]
pub async fn prepare_print(
&self,
identifier: &WindowIdentifier,
title: &str,
settings: Settings,
page_setup: PageSetup,
modal: bool,
) -> Result<PreparePrint, Error> {
let options = PreparePrintOptions::default().modal(modal);
call_request_method(
self.inner(),
&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: &WindowIdentifier,
title: &str,
fd: &impl AsRawFd,
token: Option<u32>,
modal: bool,
) -> Result<(), Error> {
let options = PrintOptions::default()
.token(token.unwrap_or(0))
.modal(modal);
call_basic_response_method(
self.inner(),
&options.handle_token,
"Print",
&(&identifier, title, Fd::from(fd.as_raw_fd()), &options),
)
.await
}
}