Add sysfs fallback for screen brightness
Some drivers/displays don't support the xbacklight stuff, so fall back to sysfs if needed. This usually will require some extra permissions setup on the user's part.
This commit is contained in:
parent
1ace254163
commit
742ff7b92c
23
README.md
23
README.md
@ -146,3 +146,26 @@ resuming.
|
||||
|
||||
The settings component is a standalone GTK app that presents a settings
|
||||
dialog, which reads from and writes to your configuration file.
|
||||
|
||||
#### Screen Brightness
|
||||
|
||||
If you enable the setting that allows `bscreensaver` to make your screen
|
||||
brightness keys work while the screen is locked, this should hopefully
|
||||
work without further intervention, if your display driver supports the
|
||||
`XBACKLIGHT` protocol. If not, `bscreensaver` will attempt to use the
|
||||
backlight controls in sysfs, which probably will not work without extra
|
||||
setup, as those controls are usually only accessible to root. You can
|
||||
give yourself (well, anyone in the `video` group) access by adding a
|
||||
udev rules file, say at `/etc/udev/rules.d/90-backlight.rules`:
|
||||
|
||||
```
|
||||
SUBSYSTEM=="backlight", ACTION=="add", \
|
||||
RUN+="/bin/chgrp video /sys/class/backlight/%k/brightness", \
|
||||
RUN+="/bin/chmod g+w /sys/class/backlight/%k/brightness"
|
||||
```
|
||||
|
||||
You may need to restart to get those settings applied, or you can just
|
||||
run those commands yourself (replacing `%k` with whatever directories
|
||||
happen to be located there). Your user account will also need to be in
|
||||
the `video` group; if it isn't, you'll probably need to log out and in
|
||||
again before any changes take effect.
|
||||
|
@ -1,5 +1,6 @@
|
||||
use log::{debug, error, warn};
|
||||
use std::{cmp, thread, time::Duration};
|
||||
use nix::unistd::{access, AccessFlags};
|
||||
use std::{cmp, thread, time::Duration, path::PathBuf, fs, io::Write};
|
||||
use xcb::{x, randr, Xid};
|
||||
|
||||
use bscreensaver_util::{BSCREENSAVER_WM_CLASS, create_atom, destroy_cursor, destroy_pixmap, destroy_gc, destroy_window};
|
||||
@ -7,8 +8,13 @@ use bscreensaver_util::{BSCREENSAVER_WM_CLASS, create_atom, destroy_cursor, dest
|
||||
const BACKLIGHT_ATOM_NAME: &[u8] = b"Backlight";
|
||||
const BACKLIGHT_FALLBACK_ATOM_NAME: &[u8] = b"BACKLIGHT";
|
||||
|
||||
enum BacklightLocation {
|
||||
XBacklight(x::Atom),
|
||||
Sysfs(PathBuf),
|
||||
}
|
||||
|
||||
struct BacklightControl {
|
||||
property: x::Atom,
|
||||
location: BacklightLocation,
|
||||
min_level: i32,
|
||||
max_level: i32,
|
||||
step: u32,
|
||||
@ -361,9 +367,11 @@ impl<'a> Monitor<'a> {
|
||||
}
|
||||
|
||||
fn get_current_brightness(&self, backlight_control: &BacklightControl) -> anyhow::Result<Option<u32>> {
|
||||
match &backlight_control.location {
|
||||
BacklightLocation::XBacklight(property) => {
|
||||
let cookie = self.conn.send_request(&randr::GetOutputProperty {
|
||||
output: self.properties.output,
|
||||
property: backlight_control.property,
|
||||
property: *property,
|
||||
r#type: x::ATOM_INTEGER,
|
||||
long_offset: 0,
|
||||
long_length: 4,
|
||||
@ -377,16 +385,28 @@ impl<'a> Monitor<'a> {
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
},
|
||||
BacklightLocation::Sysfs(path) => Ok(Some(fs::read_to_string(path)?.trim().parse::<u32>()?)),
|
||||
}
|
||||
}
|
||||
|
||||
fn set_brightness(&self, backlight_control: &BacklightControl, level: i32) -> anyhow::Result<()> {
|
||||
match &backlight_control.location {
|
||||
BacklightLocation::XBacklight(property) => {
|
||||
self.conn.send_and_check_request(&randr::ChangeOutputProperty {
|
||||
output: self.properties.output,
|
||||
property: backlight_control.property,
|
||||
property: *property,
|
||||
r#type: x::ATOM_INTEGER,
|
||||
mode: x::PropMode::Replace,
|
||||
data: &[level as u32],
|
||||
})?;
|
||||
})?
|
||||
},
|
||||
BacklightLocation::Sysfs(path) => {
|
||||
let mut f = fs::OpenOptions::new().write(true).open(path)?;
|
||||
let level_str = level.to_string();
|
||||
f.write_all(level_str.as_bytes())?;
|
||||
},
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@ -513,28 +533,57 @@ fn create_blank_cursor(conn: &xcb::Connection, root: x::Window) -> xcb::Result<x
|
||||
Ok(blank_cursor)
|
||||
}
|
||||
|
||||
fn find_backlight_control(conn: &xcb::Connection, output: randr::Output) -> xcb::Result<Option<BacklightControl>> {
|
||||
fn find_backlight_control(conn: &xcb::Connection, output: randr::Output) -> anyhow::Result<Option<BacklightControl>> {
|
||||
fn calc_step(min: i32, max: i32) -> u32 {
|
||||
cmp::min((max - min) as u32, cmp::max(10, (max - min) / 10) as u32)
|
||||
}
|
||||
|
||||
for prop_name in [BACKLIGHT_ATOM_NAME, BACKLIGHT_FALLBACK_ATOM_NAME] {
|
||||
let property = create_atom(conn, prop_name)?;
|
||||
let cookie = conn.send_request(&randr::QueryOutputProperty {
|
||||
output,
|
||||
property,
|
||||
});
|
||||
let reply = conn.wait_for_reply(cookie)?;
|
||||
if let Ok(reply) = conn.wait_for_reply(cookie) {
|
||||
let values = reply.valid_values();
|
||||
if reply.range() && values.len() == 2 {
|
||||
let min_level = values[0];
|
||||
let max_level = values[1];
|
||||
let range = max_level - min_level;
|
||||
if range > 0 {
|
||||
debug!("Found xbacklight control");
|
||||
return Ok(Some(BacklightControl {
|
||||
property,
|
||||
location: BacklightLocation::XBacklight(property),
|
||||
min_level,
|
||||
max_level,
|
||||
step: cmp::min(range as u32, cmp::max(10, (max_level - min_level) / 10) as u32),
|
||||
step: calc_step(min_level, max_level),
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Ok(entries) = fs::read_dir("/sys/class/backlight") {
|
||||
for entry in entries {
|
||||
let entry = entry?;
|
||||
let mut path = entry.path();
|
||||
path.push("brightness");
|
||||
if path.exists() && access(&path, AccessFlags::W_OK).is_ok() {
|
||||
let mut max_path = entry.path();
|
||||
max_path.push("max_brightness");
|
||||
let max_level = fs::read_to_string(max_path)?.trim().parse::<i32>()?;
|
||||
let mut cur_path = entry.path();
|
||||
cur_path.push("brightness");
|
||||
debug!("Found sysfs backlight control at {:?}", cur_path);
|
||||
return Ok(Some(BacklightControl {
|
||||
location: BacklightLocation::Sysfs(cur_path),
|
||||
min_level: 0,
|
||||
max_level,
|
||||
step: calc_step(0, max_level),
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(None)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user