kobo/display/
chr_display.rs1use std::{
2 path::PathBuf,
3 process::{Command, ExitStatus},
4};
5
6use regex::Regex;
7
8use crate::coords::{CharSpaceCoord, PixelSpaceCoord};
9
10use super::{color::EinkColor, error::DisplayError};
11
12const FBINK_VAR_PARSE: &str =
13 r"screenWidth=(\d+).*screenHeight=(\d+).*MAXCOLS=(\d+).*MAXROWS=(\d+)";
14
15pub struct CharacterDisplay {
21 fbink_path: PathBuf,
23 display_size: PixelSpaceCoord,
25 display_char_size: CharSpaceCoord,
27}
28
29impl CharacterDisplay {
30 pub fn open() -> Result<Self, DisplayError> {
32 let fbink_install_locations: Vec<PathBuf> = vec![
34 "/usr/local/kfmon/bin/fbink".parse().unwrap(),
35 "/usr/bin/fbink".parse().unwrap(),
36 ];
37 let fbink_path = fbink_install_locations
38 .iter()
39 .find(|path| path.exists())
40 .ok_or(DisplayError::FBInkNotFound)?;
41
42 let output = Command::new(fbink_path).arg("-e").output().unwrap();
44 let o = String::from_utf8(output.stdout).unwrap();
45 let matched = Regex::new(FBINK_VAR_PARSE)
46 .unwrap()
47 .captures(o.trim())
48 .unwrap();
49
50 Ok(Self {
51 fbink_path: fbink_path.to_owned(),
52 display_size: PixelSpaceCoord::new(
53 matched[1].parse().unwrap(),
54 matched[2].parse().unwrap(),
55 ),
56 display_char_size: CharSpaceCoord::new(
57 matched[3].parse().unwrap(),
58 matched[4].parse().unwrap(),
59 ),
60 })
61 }
62
63 fn fbink_exec(&self, args: Vec<String>) -> std::io::Result<ExitStatus> {
65 let mut cmd = Command::new(&self.fbink_path);
66 cmd.args(args);
67
68 if std::env::var("KOBO_RS_DEBUG_FBINK").is_ok() {
70 cmd.stdout(std::process::Stdio::inherit());
71 } else {
72 cmd.stdout(std::process::Stdio::null());
73 }
74
75 Ok(cmd.output()?.status)
76 }
77
78 pub fn get_screen_size_px(&self) -> PixelSpaceCoord {
80 self.display_size
81 }
82
83 pub fn get_screen_size_ch(&self) -> CharSpaceCoord {
85 self.display_char_size
86 }
87
88 pub fn clear_screen(&self) -> std::io::Result<ExitStatus> {
90 self.fbink_exec(vec!["-c".to_string()])
91 }
92
93 pub fn write_str(
95 &self,
96 s: &str,
97 pos: CharSpaceCoord,
98 invert_colors: bool,
99 color: Option<EinkColor>,
100 background_color: Option<EinkColor>,
101 ) -> std::io::Result<ExitStatus> {
102 let mut args = vec![
103 "-y".to_string(),
104 pos.y.to_string(),
105 "-x".to_string(),
106 pos.x.to_string(),
107 "-C".to_string(),
108 color.unwrap_or(EinkColor::Black).to_string(),
109 "-B".to_string(),
110 background_color.unwrap_or(EinkColor::White).to_string(),
111 s.to_string(),
112 ];
113
114 if invert_colors {
115 args.push("--invert".to_string());
116 }
117
118 self.fbink_exec(args)
119 }
120}