Skip to content

Commit 94badb3

Browse files
Slightly better code organization
1 parent 99db48a commit 94badb3

3 files changed

Lines changed: 305 additions & 252 deletions

File tree

src/backlight.rs

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
use std::{
2+
fs::{File, OpenOptions, self},
3+
path::PathBuf,
4+
time::Instant,
5+
io::Write
6+
};
7+
use anyhow::{Result, anyhow};
8+
use input::event::{
9+
Event, switch::{Switch, SwitchEvent, SwitchState},
10+
};
11+
use crate::TIMEOUT_MS;
12+
13+
fn find_backlight() -> Result<PathBuf> {
14+
for entry in fs::read_dir("/sys/class/backlight/")? {
15+
let entry = entry?;
16+
if entry.file_name().to_string_lossy().contains("display-pipe") {
17+
let mut path = entry.path();
18+
path.push("brightness");
19+
return Ok(path);
20+
}
21+
}
22+
Err(anyhow!("No backlight device found"))
23+
}
24+
25+
fn set_backlight(mut file: &File, value: u32) {
26+
file.write(format!("{}\n", value).as_bytes()).unwrap();
27+
}
28+
29+
pub struct BacklightManager {
30+
last_active: Instant,
31+
current_bl: u32,
32+
lid_state: SwitchState,
33+
bl_file: File
34+
}
35+
36+
impl BacklightManager {
37+
pub fn new() -> BacklightManager {
38+
let bl_path = find_backlight().unwrap();
39+
let bl_file = OpenOptions::new().write(true).open(bl_path).unwrap();
40+
BacklightManager {
41+
bl_file,
42+
lid_state: SwitchState::Off,
43+
current_bl: 42,
44+
last_active: Instant::now()
45+
}
46+
}
47+
pub fn process_event(&mut self, event: &Event) {
48+
match event {
49+
Event::Keyboard(_) | Event::Pointer(_) | Event::Touch(_) => {
50+
self.last_active = Instant::now();
51+
},
52+
Event::Switch(SwitchEvent::Toggle(toggle)) => {
53+
match toggle.switch() {
54+
Some(Switch::Lid) => {
55+
self.lid_state = toggle.switch_state();
56+
println!("Lid Switch event: {:?}", self.lid_state);
57+
if toggle.switch_state() == SwitchState::Off {
58+
self.last_active = Instant::now();
59+
}
60+
}
61+
_ => {}
62+
}
63+
}
64+
_ => {}
65+
}
66+
}
67+
pub fn update_backlight(&mut self) {
68+
let since_last_active = (Instant::now() - self.last_active).as_millis() as u64;
69+
let new_bl = if self.lid_state == SwitchState::On {
70+
0
71+
} else if since_last_active < TIMEOUT_MS as u64 {
72+
128
73+
} else if since_last_active < TIMEOUT_MS as u64 * 2 {
74+
1
75+
} else {
76+
0
77+
};
78+
if self.current_bl != new_bl {
79+
self.current_bl = new_bl;
80+
set_backlight(&self.bl_file, self.current_bl);
81+
}
82+
}
83+
}

src/display.rs

Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
use std::{
2+
fs::{File, OpenOptions, self},
3+
os::unix::io::{AsFd, BorrowedFd},
4+
path::Path,
5+
};
6+
use drm::{
7+
ClientCapability, Device as DrmDevice, buffer::DrmFourcc,
8+
control::{
9+
connector, Device as ControlDevice, property, ResourceHandle, atomic, AtomicCommitFlags,
10+
dumbbuffer::{DumbBuffer, DumbMapping}, framebuffer, ClipRect
11+
}
12+
};
13+
use anyhow::{Result, anyhow};
14+
15+
struct Card(File);
16+
impl AsFd for Card {
17+
fn as_fd(&self) -> BorrowedFd<'_> {
18+
self.0.as_fd()
19+
}
20+
}
21+
22+
impl ControlDevice for Card {}
23+
impl DrmDevice for Card {}
24+
25+
impl Card {
26+
fn open(path: &Path) -> Self {
27+
let mut options = OpenOptions::new();
28+
options.read(true);
29+
options.write(true);
30+
31+
Card(options.open(path).unwrap())
32+
}
33+
}
34+
35+
pub struct DrmBackend {
36+
card: Card,
37+
db: DumbBuffer,
38+
fb: framebuffer::Handle
39+
}
40+
41+
impl Drop for DrmBackend {
42+
fn drop(&mut self) {
43+
self.card.destroy_framebuffer(self.fb).unwrap();
44+
self.card.destroy_dumb_buffer(self.db).unwrap();
45+
}
46+
}
47+
48+
49+
fn find_prop_id<T: ResourceHandle>(
50+
card: &Card,
51+
handle: T,
52+
name: &'static str,
53+
) -> Result<property::Handle> {
54+
let props = card.get_properties(handle)?;
55+
for id in props.as_props_and_values().0 {
56+
let info = card.get_property(*id)?;
57+
if info.name().to_str()? == name {
58+
return Ok(*id);
59+
}
60+
}
61+
return Err(anyhow!("Property not found"));
62+
}
63+
64+
fn try_open_card(path: &Path) -> Result<DrmBackend> {
65+
let card = Card::open(path);
66+
card.set_client_capability(ClientCapability::UniversalPlanes, true)?;
67+
card.set_client_capability(ClientCapability::Atomic, true)?;
68+
card.acquire_master_lock()?;
69+
70+
71+
let res = card.resource_handles()?;
72+
let coninfo = res
73+
.connectors()
74+
.iter()
75+
.flat_map(|con| card.get_connector(*con, true))
76+
.collect::<Vec<_>>();
77+
let crtcinfo = res
78+
.crtcs()
79+
.iter()
80+
.flat_map(|crtc| card.get_crtc(*crtc))
81+
.collect::<Vec<_>>();
82+
83+
let con = coninfo
84+
.iter()
85+
.find(|&i| i.state() == connector::State::Connected)
86+
.ok_or(anyhow!("No connected connectors found"))?;
87+
88+
let &mode = con.modes().get(0).ok_or(anyhow!("No modes found"))?;
89+
let (disp_width, disp_height) = mode.size();
90+
if disp_height / disp_width < 30 {
91+
return Err(anyhow!("This does not look like a touchbar"));
92+
}
93+
let crtc = crtcinfo.get(0).ok_or(anyhow!("No crtcs found"))?;
94+
let fmt = DrmFourcc::Xrgb8888;
95+
let db = card.create_dumb_buffer((64, disp_height.into()), fmt, 32)?;
96+
97+
let fb = card.add_framebuffer(&db, 24, 32)?;
98+
let plane = *card.plane_handles()?.get(0).ok_or(anyhow!("No planes found"))?;
99+
100+
let mut atomic_req = atomic::AtomicModeReq::new();
101+
atomic_req.add_property(
102+
con.handle(),
103+
find_prop_id(&card, con.handle(), "CRTC_ID")?,
104+
property::Value::CRTC(Some(crtc.handle())),
105+
);
106+
let blob = card.create_property_blob(&mode)?;
107+
108+
atomic_req.add_property(
109+
crtc.handle(),
110+
find_prop_id(&card, crtc.handle(), "MODE_ID")?,
111+
blob,
112+
);
113+
atomic_req.add_property(
114+
crtc.handle(),
115+
find_prop_id(&card, crtc.handle(), "ACTIVE")?,
116+
property::Value::Boolean(true),
117+
);
118+
atomic_req.add_property(
119+
plane,
120+
find_prop_id(&card, plane, "FB_ID")?,
121+
property::Value::Framebuffer(Some(fb)),
122+
);
123+
atomic_req.add_property(
124+
plane,
125+
find_prop_id(&card, plane, "CRTC_ID")?,
126+
property::Value::CRTC(Some(crtc.handle())),
127+
);
128+
atomic_req.add_property(
129+
plane,
130+
find_prop_id(&card, plane, "SRC_X")?,
131+
property::Value::UnsignedRange(0),
132+
);
133+
atomic_req.add_property(
134+
plane,
135+
find_prop_id(&card, plane, "SRC_Y")?,
136+
property::Value::UnsignedRange(0),
137+
);
138+
atomic_req.add_property(
139+
plane,
140+
find_prop_id(&card, plane, "SRC_W")?,
141+
property::Value::UnsignedRange((mode.size().0 as u64) << 16),
142+
);
143+
atomic_req.add_property(
144+
plane,
145+
find_prop_id(&card, plane, "SRC_H")?,
146+
property::Value::UnsignedRange((mode.size().1 as u64) << 16),
147+
);
148+
atomic_req.add_property(
149+
plane,
150+
find_prop_id(&card, plane, "CRTC_X")?,
151+
property::Value::SignedRange(0),
152+
);
153+
atomic_req.add_property(
154+
plane,
155+
find_prop_id(&card, plane, "CRTC_Y")?,
156+
property::Value::SignedRange(0),
157+
);
158+
atomic_req.add_property(
159+
plane,
160+
find_prop_id(&card, plane, "CRTC_W")?,
161+
property::Value::UnsignedRange(mode.size().0 as u64),
162+
);
163+
atomic_req.add_property(
164+
plane,
165+
find_prop_id(&card, plane, "CRTC_H")?,
166+
property::Value::UnsignedRange(mode.size().1 as u64),
167+
);
168+
169+
card.atomic_commit(AtomicCommitFlags::ALLOW_MODESET, atomic_req)?;
170+
171+
172+
Ok(DrmBackend { card, db, fb })
173+
}
174+
175+
impl DrmBackend {
176+
pub fn open_card() -> Result<DrmBackend> {
177+
for entry in fs::read_dir("/dev/dri/")? {
178+
let entry = entry?;
179+
if !entry.file_name().to_string_lossy().starts_with("card") {
180+
continue
181+
}
182+
match try_open_card(&entry.path()) {
183+
Ok(card) => return Ok(card),
184+
Err(_) => {}
185+
}
186+
}
187+
Err(anyhow!("No touchbar device found"))
188+
}
189+
pub fn dirty(&self, clips: &[ClipRect]) -> Result<()> {
190+
Ok(self.card.dirty_framebuffer(self.fb, clips)?)
191+
}
192+
pub fn map(&mut self) -> Result<DumbMapping> {
193+
Ok(self.card.map_dumb_buffer(&mut self.db)?)
194+
}
195+
}

0 commit comments

Comments
 (0)