Do not send duplex to printers without two-sided support (#6673)

On Windows the printer list reports whether a driver supports two-sided printing, but the job still asked for it anyway, so duplex jobs printed single-sided or misaligned on printers such as the reported Brother model.

Leave duplex unset for a printer reported as not two-sided, so that printer keeps its own setting, while printers that support two-sided or report no capability keep the chosen setting.

Test: duplex_is_not_sent_to_a_printer_without_two_sided failed before the change and passes after.

Co-authored-by: eliets2 <287273517+eliets2@users.noreply.github.com>
Co-authored-by: FredApps <153173854+FredApps@users.noreply.github.com>
This commit is contained in:
authored and GitHub committed 2026-11-10 17:48:48 +01:00
1 parent fe70ecce73
commit 8559306f77
2 files changed
+45 -2

No files matched your search

+32
View File
@@ -832,6 +832,38 @@ mod tests {
assert!(cut.settings(4, &[]).is_err());
}
/// #3208: long or short edge goes to a printer whose driver doesn't take two-sided settings
/// as no duplex setting at all, so the driver keeps its own instead of refusing the job; Off
/// still reaches it, a printer that can or whose support is unknown still gets the choice,
/// and a stale long-edge choice doesn't block cut and stack. The printers are listed as the
/// dialog lists them (#3554), drivers unasked, with each answer in `two_sided`.
#[test]
fn duplex_is_not_sent_to_a_printer_without_two_sided() {
let draft = |name: &str, duplex| PrintDraft {
printers: ["Office", "Duplexer", "Network"]
.map(|n| spool::Printer { name: n.into(), default: n == "Office", two_sided: None, description: String::new() })
.to_vec(),
two_sided: [("Office".to_string(), Some(false)), ("Duplexer".to_string(), Some(true))].into_iter().collect(),
printer: Some(name.into()),
duplex,
..PrintDraft::default()
};
for duplex in [spool::Duplex::LongEdge, spool::Duplex::ShortEdge] {
assert_eq!(draft("Office", Some(duplex)).job("report.pdf").duplex, None, "{duplex:?} to a printer without two-sided");
assert_eq!(draft("Duplexer", Some(duplex)).job("report.pdf").duplex, Some(duplex));
assert_eq!(draft("Network", Some(duplex)).job("report.pdf").duplex, Some(duplex), "unknown support keeps the choice");
}
assert_eq!(draft("Office", Some(spool::Duplex::Off)).job("report.pdf").duplex, Some(spool::Duplex::Off), "Off still reaches it");
assert_eq!(draft("Office", None).job("report.pdf").duplex, None);
// A long-edge choice left from another printer doesn't block cut and stack on this one.
let mut cut = draft("Office", Some(spool::Duplex::LongEdge));
(cut.handling, cut.order) = (Handling::Multiple, PageOrder::CutStack);
assert!(cut.settings(4, &[]).is_ok());
assert_eq!(cut.job("report.pdf").duplex, Some(spool::Duplex::Off));
cut.printer = Some("Duplexer".into());
assert!(cut.settings(4, &[]).is_err(), "still refused where it would print two-sided");
}
/// #5772: a booklet's both sides ask the printer for the short edge, unless its driver doesn't
/// take two-sided settings: it would refuse the job, so its own setting (manual two-sided, say)
/// prints it. One side on its own stays one-sided.
+13 -2
View File
@@ -255,7 +255,7 @@ impl PrintDraft {
area: Some(area),
});
}
if self.cut_and_stack() && matches!(self.duplex, Some(spool::Duplex::LongEdge | spool::Duplex::ShortEdge)) {
if self.cut_and_stack() && matches!(self.chosen_duplex(), Some(spool::Duplex::LongEdge | spool::Duplex::ShortEdge)) {
return Err("Cut and stack needs Two-sided: Off. Print single-sided sheets.".into());
}
let range = match self.which {
@@ -322,6 +322,17 @@ impl PrintDraft {
p.two_sided.or_else(|| self.two_sided.get(&p.name).copied().flatten())
}
/// The Two-sided choice as the chosen printer can take it: long or short edge is left out for
/// a printer whose driver doesn't take two-sided settings from other programs, so its own
/// setting applies instead of the job being refused (#3208). Off and the printer's default
/// stay as chosen: one-sided is accepted by every driver.
fn chosen_duplex(&self) -> Option<spool::Duplex> {
match self.duplex {
Some(spool::Duplex::LongEdge | spool::Duplex::ShortEdge) if self.printer_two_sided() == Some(false) => None,
chosen => chosen,
}
}
/// The spooler job for this print: the dialog's copies, two-sided and colour settings, the
/// driver options changed from the printer's defaults, and the chosen paper.
pub fn job(&self, title: &str) -> spool::Job {
@@ -337,7 +348,7 @@ impl PrintDraft {
} else if self.handling == Handling::Booklet {
print::booklet_job_duplex(self.booklet_subset, self.printer_two_sided())
} else {
self.duplex
self.chosen_duplex()
},
scaling: spool::Scaling::Exact,
grayscale: print::driver_needs_grayscale(self.grayscale, self.raster()),