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
|
The settings component is a standalone GTK app that presents a settings
|
||||||
dialog, which reads from and writes to your configuration file.
|
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 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 xcb::{x, randr, Xid};
|
||||||
|
|
||||||
use bscreensaver_util::{BSCREENSAVER_WM_CLASS, create_atom, destroy_cursor, destroy_pixmap, destroy_gc, destroy_window};
|
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_ATOM_NAME: &[u8] = b"Backlight";
|
||||||
const BACKLIGHT_FALLBACK_ATOM_NAME: &[u8] = b"BACKLIGHT";
|
const BACKLIGHT_FALLBACK_ATOM_NAME: &[u8] = b"BACKLIGHT";
|
||||||
|
|
||||||
|
enum BacklightLocation {
|
||||||
|
XBacklight(x::Atom),
|
||||||
|
Sysfs(PathBuf),
|
||||||
|
}
|
||||||
|
|
||||||
struct BacklightControl {
|
struct BacklightControl {
|
||||||
property: x::Atom,
|
location: BacklightLocation,
|
||||||
min_level: i32,
|
min_level: i32,
|
||||||
max_level: i32,
|
max_level: i32,
|
||||||
step: u32,
|
step: u32,
|
||||||
@ -361,9 +367,11 @@ impl<'a> Monitor<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn get_current_brightness(&self, backlight_control: &BacklightControl) -> anyhow::Result<Option<u32>> {
|
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 {
|
let cookie = self.conn.send_request(&randr::GetOutputProperty {
|
||||||
output: self.properties.output,
|
output: self.properties.output,
|
||||||
property: backlight_control.property,
|
property: *property,
|
||||||
r#type: x::ATOM_INTEGER,
|
r#type: x::ATOM_INTEGER,
|
||||||
long_offset: 0,
|
long_offset: 0,
|
||||||
long_length: 4,
|
long_length: 4,
|
||||||
@ -377,16 +385,28 @@ impl<'a> Monitor<'a> {
|
|||||||
} else {
|
} else {
|
||||||
Ok(None)
|
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<()> {
|
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 {
|
self.conn.send_and_check_request(&randr::ChangeOutputProperty {
|
||||||
output: self.properties.output,
|
output: self.properties.output,
|
||||||
property: backlight_control.property,
|
property: *property,
|
||||||
r#type: x::ATOM_INTEGER,
|
r#type: x::ATOM_INTEGER,
|
||||||
mode: x::PropMode::Replace,
|
mode: x::PropMode::Replace,
|
||||||
data: &[level as u32],
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -513,28 +533,57 @@ fn create_blank_cursor(conn: &xcb::Connection, root: x::Window) -> xcb::Result<x
|
|||||||
Ok(blank_cursor)
|
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] {
|
for prop_name in [BACKLIGHT_ATOM_NAME, BACKLIGHT_FALLBACK_ATOM_NAME] {
|
||||||
let property = create_atom(conn, prop_name)?;
|
let property = create_atom(conn, prop_name)?;
|
||||||
let cookie = conn.send_request(&randr::QueryOutputProperty {
|
let cookie = conn.send_request(&randr::QueryOutputProperty {
|
||||||
output,
|
output,
|
||||||
property,
|
property,
|
||||||
});
|
});
|
||||||
let reply = conn.wait_for_reply(cookie)?;
|
if let Ok(reply) = conn.wait_for_reply(cookie) {
|
||||||
let values = reply.valid_values();
|
let values = reply.valid_values();
|
||||||
if reply.range() && values.len() == 2 {
|
if reply.range() && values.len() == 2 {
|
||||||
let min_level = values[0];
|
let min_level = values[0];
|
||||||
let max_level = values[1];
|
let max_level = values[1];
|
||||||
let range = max_level - min_level;
|
let range = max_level - min_level;
|
||||||
if range > 0 {
|
if range > 0 {
|
||||||
|
debug!("Found xbacklight control");
|
||||||
return Ok(Some(BacklightControl {
|
return Ok(Some(BacklightControl {
|
||||||
property,
|
location: BacklightLocation::XBacklight(property),
|
||||||
min_level,
|
min_level,
|
||||||
max_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)
|
Ok(None)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user