Skip to main content

ipp_printer_app/
device.rs

1//! [`DeviceBackend`] trait: enumerate physical devices, resolve driver names,
2//! poll live status.
3
4use crate::flags::PrinterReason;
5use crate::printer::PrinterConfig;
6
7/// The media currently loaded in a device, as reported by a live poll. Drives
8/// the dynamic `media-ready` / `media-col-ready` IPP attributes.
9#[derive(Debug, Clone, PartialEq, Eq)]
10pub struct ReadyMedia {
11    /// PWG self-describing media name (e.g. `om_40x30mm_40x30mm`).
12    pub name: String,
13    /// Width/height in hundredths of a millimetre (PWG units).
14    pub size_hmm: [i32; 2],
15    /// PWG media-type keyword (e.g. `labels`).
16    pub media_type: String,
17}
18
19/// Live status reported by [`DeviceBackend::poll_status`]. Returning `None`
20/// from the poll means "no update"; returning `Some(PollStatus)` replaces the
21/// reasons and, when the optional fields are set, the dynamic media/supply
22/// attributes.
23#[derive(Debug, Clone)]
24pub struct PollStatus {
25    /// Fresh `printer-state-reasons`.
26    pub reasons: PrinterReason,
27    /// Currently-loaded media, if the device can report it.
28    pub ready_media: Option<ReadyMedia>,
29    /// Remaining-supply level 0–100 (e.g. labels left on the roll), if known.
30    pub supply_percent: Option<u8>,
31}
32
33impl Default for PollStatus {
34    fn default() -> Self {
35        Self {
36            reasons: PrinterReason::empty(),
37            ready_media: None,
38            supply_percent: None,
39        }
40    }
41}
42
43impl PollStatus {
44    /// Convenience constructor for backends that only report reasons.
45    pub fn from_reasons(reasons: PrinterReason) -> Self {
46        Self {
47            reasons,
48            ..Default::default()
49        }
50    }
51}
52
53/// Enumerate physical printers and report their live health.
54///
55/// Implementations describe how to discover devices (e.g. via sysfs, BlueZ,
56/// USB enumeration) and how to map their identifying strings to a driver
57/// name registered with the framework.
58pub trait DeviceBackend: Send + Sync {
59    /// Call `emit(info, uri, device_id)` for each discovered device. The
60    /// closure returns `true` to continue enumeration, `false` to stop early.
61    fn list(&self, emit: &mut dyn FnMut(&str, &str, &str) -> bool);
62
63    /// Map a device's IEEE 1284 `device-id` string and URI to a driver name
64    /// that this backend recognises. Return `None` for "this isn't one of
65    /// mine, skip it".
66    fn driver_for_device(&self, device_id: &str, device_uri: &str) -> Option<String>;
67
68    /// Query live status for a registered printer. The background status loop
69    /// calls this on each idle printer and updates the IPP attributes when the
70    /// value changes. Returning `None` means "no update" (keep whatever the
71    /// registry already holds); returning `Some` carries the fresh reasons and,
72    /// optionally, the loaded media and remaining-supply level.
73    fn poll_status(&self, _config: &PrinterConfig) -> Option<PollStatus> {
74        None
75    }
76
77    /// Handle an `Identify-Printer` request (PWG 5100.14 §5.1) — make the
78    /// physical device announce itself (beep, flash an LED, …). `actions`
79    /// holds the requested `identify-actions` keywords (`display`, `sound`,
80    /// `flash`, `speak`); an empty slice means "use the default action".
81    /// Default: no-op.
82    fn identify(&self, _config: &PrinterConfig, _actions: &[String]) {}
83}