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
Show file tree
Hide file tree
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
5 changes: 3 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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 = [ ]
Expand All @@ -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 }
Expand Down
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)]
Expand Down Expand Up @@ -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
Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand Down
32 changes: 28 additions & 4 deletions src/webkitgtk/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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(())
}

Expand Down
6 changes: 5 additions & 1 deletion src/webview2/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>>,
Expand Down
39 changes: 20 additions & 19 deletions src/wkwebview/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::{
Expand All @@ -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 {
Expand Down Expand Up @@ -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 {
Expand All @@ -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
Expand Down
Loading