Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

enhance: Add API to allow print options #1324

Open
wants to merge 1 commit into
base: dev
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
enhance: Add API to allow print options
Mildred KiLya authored and mildred committed Jul 23, 2024
commit 8e8c98864e2713b7e562f7e14bc0adacd36afe33
5 changes: 3 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -15,7 +15,7 @@ exclude = [ "/.changes", "/.github", "/audits", "/wry-logo.svg" ]

[package.metadata.docs.rs]
no-default-features = true
features = [ "drag-drop", "protocol", "os-webview" ]
features = [ "drag-drop", "protocol", "os-webview", "serde" ]
targets = [
"x86_64-unknown-linux-gnu",
"x86_64-pc-windows-msvc",
@@ -26,7 +26,7 @@ rustdoc-args = [ "--cfg", "docsrs" ]

[features]
default = [ "drag-drop", "objc-exception", "protocol", "os-webview" ]
serde = [ "dpi/serde" ]
serde = [ "dep:serde", "dpi/serde" ]
objc-exception = [ "objc/exception" ]
drag-drop = [ ]
protocol = [ ]
@@ -53,6 +53,7 @@ thiserror = "1.0"
http = "1.1"
raw-window-handle = { version = "0.6", features = [ "std" ] }
dpi = "0.1"
serde = { version = "1", features = ["serde_derive"], optional = true }

[target."cfg(any(target_os = \"linux\", target_os = \"dragonfly\", target_os = \"freebsd\", target_os = \"openbsd\", target_os = \"netbsd\"))".dependencies]
javascriptcore-rs = { version = "=1.1.2", features = [ "v2_28" ], optional = true }
4 changes: 4 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
/// Convenient type alias of Result type for wry.
pub type Result<T> = std::result::Result<T, Error>;

use crate::PrintOption;

/// Errors returned by wry.
#[non_exhaustive]
#[derive(thiserror::Error, Debug)]
@@ -61,4 +63,6 @@ pub enum Error {
CustomProtocolTaskInvalid,
#[error("Failed to register URL scheme: {0}, could be due to invalid URL scheme or the scheme is already registered.")]
UrlSchemeRegisterError(String),
#[error("Invalid print option {0}")]
PrintOptionError(PrintOption),
}
39 changes: 38 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
@@ -1285,6 +1285,39 @@ impl<'a> WebViewBuilderExtUnix<'a> for WebViewBuilder<'a> {
}
}

#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};

/// Print margins in millimeters
#[derive(Debug, Default, Copy, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct PrintMargin {
pub top: f32,
pub right: f32,
pub bottom: f32,
pub left: f32,
}

/// The print options
///
/// When printing, multiple options can be passed to the print function causing it to alter the
/// printing behavior. If a backend does not support a print option, it can return the option as an
/// error using: `return Err(Error::PrintOptionError(opt.clone()))`
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum PrintOption {
Silent(bool),
Margins(PrintMargin)
}

impl std::fmt::Display for PrintOption {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?}", self)
}
}

impl std::error::Error for PrintOption {}

/// The fundamental type to present a [`WebView`].
///
/// [`WebViewBuilder`] / [`WebView`] are the basic building blocks to construct WebView contents and
@@ -1372,7 +1405,11 @@ impl WebView {

/// Launch print modal for the webview content.
pub fn print(&self) -> Result<()> {
self.webview.print()
self.webview.print_with_options(&[])
}

pub fn print_with_options(&self, options: &[PrintOption]) -> Result<()> {
self.webview.print_with_options(options)
}

/// Open the web inspector which is usually called dev tool.
32 changes: 28 additions & 4 deletions src/webkitgtk/mod.rs
Original file line number Diff line number Diff line change
@@ -42,7 +42,7 @@ pub use web_context::WebContextImpl;

use crate::{
proxy::ProxyConfig, web_context::WebContext, Error, PageLoadEvent, Rect, Result,
WebViewAttributes, RGBA,
WebViewAttributes, RGBA, PrintOption
};

use self::web_context::WebContextExt;
@@ -558,9 +558,33 @@ impl InnerWebView {
is_inspector_open
}

pub fn print(&self) -> Result<()> {
let print = webkit2gtk::PrintOperation::new(&self.webview);
print.run_dialog(None::<&gtk::Window>);
pub fn print_with_options(&self, options: &[PrintOption]) -> Result<()> {
let page_setup = gtk::PageSetup::new();
let mut silent: bool = false;

for opt in options.iter() {
match opt {
PrintOption::Silent(s) => {
silent = *s
},
PrintOption::Margins(m) => {
page_setup.set_left_margin(f64::from(m.left), gtk::Unit::Mm);
page_setup.set_right_margin(f64::from(m.right), gtk::Unit::Mm);
page_setup.set_top_margin(f64::from(m.top), gtk::Unit::Mm);
page_setup.set_bottom_margin(f64::from(m.bottom), gtk::Unit::Mm);
}
}
}

let mut print = webkit2gtk::PrintOperation::builder();
print = print.web_view(&self.webview);
print = print.page_setup(&page_setup);

if silent {
print.build().print();
} else {
print.build().run_dialog(None::<&gtk::Window>);
}
Ok(())
}

6 changes: 5 additions & 1 deletion src/webview2/mod.rs
Original file line number Diff line number Diff line change
@@ -1317,7 +1317,11 @@ impl InnerWebView {
Ok(())
}

pub fn print(&self) -> Result<()> {
pub fn print_with_options(&self, options: &[PrintOption]) -> Result<()> {
for opt in options.iter() {
return Err(Error::PrintOptionError(opt.clone()))
}

self.eval(
"window.print()",
None::<Box<dyn FnOnce(String) + Send + 'static>>,
39 changes: 20 additions & 19 deletions src/wkwebview/mod.rs
Original file line number Diff line number Diff line change
@@ -64,6 +64,7 @@ use crate::{
navigation::{add_navigation_mathods, drop_navigation_methods, set_navigation_methods},
},
Error, PageLoadEvent, Rect, RequestAsyncResponder, Result, WebContext, WebViewAttributes, RGBA,
PrintOption, PrintMargin
};

use http::{
@@ -84,17 +85,8 @@ const NS_JSON_WRITING_FRAGMENTS_ALLOWED: u64 = 4;
static COUNTER: Counter = Counter::new();
static WEBVIEW_IDS: Lazy<Mutex<HashSet<u32>>> = Lazy::new(Default::default);

#[derive(Debug, Default, Copy, Clone)]
pub struct PrintMargin {
pub top: f32,
pub right: f32,
pub bottom: f32,
pub left: f32,
}

#[derive(Debug, Default, Clone)]
pub struct PrintOptions {
pub margins: PrintMargin,
fn mm_to_printer_points(mm: f32) -> f32 {
mm * 2.8452755906
}

pub(crate) struct InnerWebView {
@@ -1173,11 +1165,20 @@ r#"Object.defineProperty(window, 'ipc', {
}
}

pub fn print(&self) -> crate::Result<()> {
self.print_with_options(&PrintOptions::default())
}
pub fn print_with_options(&self, options: &[WebViewPrintOption]) -> Result<()> {
let mut margins: PrintMargin = PrintMargin::default();

for opt in options.iter() {
match opt {
PrintOption::Margins(m) => {
margins = m;
},
_ => {
return Err(Error::PrintOptionError(opt.clone()))
}
}
}

pub fn print_with_options(&self, options: &PrintOptions) -> crate::Result<()> {
// Safety: objc runtime calls are unsafe
#[cfg(target_os = "macos")]
unsafe {
@@ -1189,10 +1190,10 @@ r#"Object.defineProperty(window, 'ipc', {
// Create a shared print info
let print_info: id = msg_send![class!(NSPrintInfo), sharedPrintInfo];
let print_info: id = msg_send![print_info, init];
let () = msg_send![print_info, setTopMargin:CGFloat::from(options.margins.top)];
let () = msg_send![print_info, setRightMargin:CGFloat::from(options.margins.right)];
let () = msg_send![print_info, setBottomMargin:CGFloat::from(options.margins.bottom)];
let () = msg_send![print_info, setLeftMargin:CGFloat::from(options.margins.left)];
let () = msg_send![print_info, setTopMargin:CGFloat::from(mm_to_printer_points(margins.top))];
let () = msg_send![print_info, setRightMargin:CGFloat::from(mm_to_printer_points(margins.right))];
let () = msg_send![print_info, setBottomMargin:CGFloat::from(mm_to_printer_points(margins.bottom))];
let () = msg_send![print_info, setLeftMargin:CGFloat::from(mm_to_printer_points(margins.left))];
// Create new print operation from the webview content
let print_operation: id = msg_send![self.webview, printOperationWithPrintInfo: print_info];
// Allow the modal to detach from the current thread and be non-blocker