Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 10 additions & 9 deletions docs/modules/Brightness.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,16 @@ Allows to change the respective value via scrolling.

> Type: `brightness`

| Name | Type | Default | Profile? | Description |
|------------------------|-------------------------|-----------------|----------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `format` | `string` | `{percentage}%` | Yes | Format string to use for the widget button label. |
| `icon_label` | `string` | `null` | Yes | Icon to show alongside the label. Supports [image](images) icons. |
| `mode.type` | `systemd` or `keyboard` | `systemd` | No | The data backend of the brightness module, this can be either the KdbBrightness dbus which is good for keyboard data, or the more general login1 dbus in combination with /sys/class/{subsystem}. |
| `mode.subsystem` | `backlight` or `leds` | `backlight` | No | The name of the subsystem use on the filesystem. |
| `mode.name` | `string` or `null` | `null` | No | When set, using the specific directory, within /sys/class/{subsystem} . If null the module will try to find a reasonable default. |
| `smooth_scroll_speed` | `float` | `1.0` | No | Controls how fast the brightness is changed, e.g. in case touchpad scrolling is used. Negative values swap the scroll direction. |
| `use_default_profiles` | `boolean` | `true` | No | Whether default profiles should be used. |
| Name | Type | Default | Profile? | Description |
|------------------------|-------------------------|-----------------------|-------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `format` | `string` | `{percentage}%` | Yes | Format string to use for the widget button label. |
| `icon_label` | `string` | `null` | Yes | Icon to show alongside the label. Supports [image](images) icons. |
| `mode.type` | `systemd` or `keyboard` | `systemd` | No | The data backend of the brightness module, this can be either the KdbBrightness dbus which is good for keyboard data, or the more general login1 dbus in combination with /sys/class/{subsystem}. |
| `mode.subsystem` | `backlight` or `leds` | `backlight` | No | The name of the subsystem use on the filesystem. |
| `mode.name` | `string` or `null` | `null` | No | When set, using the specific directory, within /sys/class/{subsystem} . If null the module will try to find a reasonable default. |
| `scale` | `automatic`, `linear`, `gamma2_2`, or `gamma2_4`| `automatic` | No | Sets the scaling strategy for converting brightness values into percentages. Automatic will try to fit linear values into a Gamma 2.4 transfert function to better match our perception of light. You can force other conversion by selecting them.
| `smooth_scroll_speed` | `float` | `1.0` | No | Controls how fast the brightness is changed, e.g. in case touchpad scrolling is used. Negative values swap the scroll direction. |
| `use_default_profiles` | `boolean` | `true` | No | Whether default profiles should be used. |

Information on the profiles system can be found [here](profiles).

Expand Down
2 changes: 1 addition & 1 deletion src/clients/brightness/dbus_keyboard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use zbus::proxy;
#[proxy(
interface = "org.freedesktop.UPower.KbdBacklight",
default_service = "org.freedesktop.UPower",
default_path = "/org/freedesktop/UPower/KbdBacklight"
assume_defaults = false
)]
pub trait KbdBacklight {
/// GetMaxBrightness method
Expand Down
73 changes: 55 additions & 18 deletions src/clients/brightness/fs_reader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,18 @@ pub enum ReadParseError {
Parse(std::num::ParseIntError),
}

impl From<std::io::Error> for ReadParseError {
fn from(value: std::io::Error) -> Self {
Self::Read(value)
}
}

impl From<std::num::ParseIntError> for ReadParseError {
fn from(value: std::num::ParseIntError) -> Self {
Self::Parse(value)
}
}

impl fmt::Display for ReadParseError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Expand All @@ -22,27 +34,52 @@ impl std::error::Error for ReadParseError {}

const SYS_PATH: &str = "/sys/class";

pub fn brightness(subsystem: &str, name: &str) -> Result<i32, ReadParseError> {
/// Build path from `subsystem` and `name`.
///
/// The path built has [SYS_PATH] as a prefix.
fn build_path(subsystem: &str, name: &str) -> PathBuf {
let mut path = PathBuf::from(SYS_PATH);
path.push(subsystem);
path.push(name);
path.push("brightness");
let s = fs::read_to_string(path).map_err(ReadParseError::Read)?;
let value = s.trim().parse::<i32>().map_err(ReadParseError::Parse)?;
Ok(value)
path
}

pub fn max_brightness(subsystem: &str, name: &str) -> Result<i32, ReadParseError> {
let mut path = PathBuf::from(SYS_PATH);
path.push(subsystem);
path.push(name);
path.push("max_brightness");
let s = fs::read_to_string(path).map_err(ReadParseError::Read)?;
let value = s.trim().parse::<i32>().map_err(ReadParseError::Parse)?;
Ok(value)
/// Read an [i32] for a specific `attribute`.
///
/// Select within [SYS_PATH] the `subsystem` and the `driver` for the `attribute` you want to read an [i32] from.
fn read_i32_from_file(
subsystem: &str,
driver: &str,
attribute: &str,
) -> Result<i32, ReadParseError> {
let mut path = build_path(subsystem, driver);
path.push(attribute);
let s = fs::read_to_string(path)?;
Ok(s.trim().parse::<i32>()?)
}

/// Get the `brightness` attribute from the `subsystem` and `driver` within [SYS_PATH].
pub fn brightness(subsystem: &str, driver: &str) -> Result<i32, ReadParseError> {
read_i32_from_file(subsystem, driver, "brightness")
}

/// Get the `max_brightness` attribute from the `subsystem` and `driver` within [SYS_PATH].
pub fn max_brightness(subsystem: &str, driver: &str) -> Result<i32, ReadParseError> {
read_i32_from_file(subsystem, driver, "max_brightness")
}

/// Get the scaling of the brightness.
///
/// Possible values are:
/// - "unknown"
/// - "linear"
pub(super) fn scaling(subsystem: &str, driver: &str) -> Result<Box<str>, ReadParseError> {
let mut path = build_path(subsystem, driver);
path.push("scale");
Ok(Box::from(fs::read_to_string(path)?.as_str()))
}

pub(super) fn available_resource_names(subsystem: &str) -> Vec<String> {
pub(super) fn available_resource_names(subsystem: &str) -> Vec<Box<str>> {
let mut path = PathBuf::from(SYS_PATH);
path.push(subsystem);

Expand All @@ -53,15 +90,15 @@ pub(super) fn available_resource_names(subsystem: &str) -> Vec<String> {
if path.is_dir()
&& let Some(name) = entry.file_name().to_str()
{
resource_names.push(name.to_string());
resource_names.push(Box::from(name));
}
}
}
resource_names.sort();
resource_names
}

pub fn default_resource_name(subsystem: &str) -> Option<String> {
pub fn default_resource_name(subsystem: &str) -> Option<Box<str>> {
let possible_files = available_resource_names(subsystem);

match subsystem {
Expand All @@ -82,8 +119,8 @@ pub fn default_resource_name(subsystem: &str) -> Option<String> {

TO_CHECK
.iter()
.find(|item| possible_files.iter().any(|v| v == **item))
.map(ToString::to_string)
.find(|&item| possible_files.iter().any(|v| **v == **item))
.map(|s| Box::from(*s))
}
"leds" => {
// almost all leds have the same postfix
Expand Down
65 changes: 58 additions & 7 deletions src/clients/brightness/ironvar.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
use super::{brightness, fs_reader::available_resource_names, max_brightness};
use crate::await_sync;
use std::sync::Arc;
use crate::{
await_sync,
clients::brightness::{BrightnessDevice, BrightnessTypeProperties},
lock,
};
use std::{
collections::HashMap,
sync::{Arc, Mutex},
};

const KDB_NAMESPACE: &str = "kbd_backlight";
const KDB_KEY_MAX_BRIGHTNESS: &str = "max";
Expand All @@ -10,8 +17,12 @@ const BACKLIGHT_MAX_NAMESPACE: &str = "backlight_max";
const LEDS_CURRENT_NAMESPACE: &str = "leds_current";
const LEDS_MAX_NAMESPACE: &str = "leds_max";

#[derive(Debug)]
pub(super) struct KbdBacklight {
keyboards: Arc<Mutex<HashMap<Box<str>, BrightnessDevice>>>,
}

#[derive(Debug)]
pub(super) struct KbdBacklightDevice {
keyboard: Arc<super::KbdBacklightProxy<'static>>,
}

Expand All @@ -28,6 +39,40 @@ enum Property {
}

impl crate::ironvar::Namespace for KbdBacklight {
fn get(&self, _: &str) -> Option<String> {
None
}

fn list(&self) -> Vec<String> {
Vec::new()
}

fn namespaces(&self) -> Vec<String> {
let mut namespaces = Vec::new();

let devices = lock!(self.keyboards);

for (key, values) in devices.iter() {
if matches!(values.properties, BrightnessTypeProperties::Kbd { .. }) {
namespaces.push(key.to_string());
}
}

namespaces
}

fn get_namespace(&self, key: &str) -> Option<crate::ironvar::NamespaceTrait> {
let devices = lock!(self.keyboards);
match &devices.get(key)?.properties {
BrightnessTypeProperties::Kbd { proxy, .. } => Some(Arc::new(KbdBacklightDevice {
keyboard: Arc::new(proxy.clone()),
})),
BrightnessTypeProperties::SysFs { .. } => None,
}
}
}

impl crate::ironvar::Namespace for KbdBacklightDevice {
fn get(&self, key: &str) -> Option<String> {
match key {
KDB_KEY_MAX_BRIGHTNESS => await_sync(self.keyboard.get_max_brightness())
Expand All @@ -49,7 +94,7 @@ impl crate::ironvar::Namespace for KbdBacklight {
}

fn namespaces(&self) -> Vec<String> {
vec![]
Vec::new()
}

fn get_namespace(&self, _key: &str) -> Option<crate::ironvar::NamespaceTrait> {
Expand All @@ -69,6 +114,9 @@ impl crate::ironvar::Namespace for FsBacklight {

fn list(&self) -> Vec<String> {
available_resource_names(&self.subsystem)
.iter()
.map(|s| s.to_string())
.collect()
}

fn namespaces(&self) -> Vec<String> {
Expand Down Expand Up @@ -101,9 +149,12 @@ impl crate::ironvar::Namespace for super::Client {

fn get_namespace(&self, key: &str) -> Option<crate::ironvar::NamespaceTrait> {
match key {
KDB_NAMESPACE => Some(Arc::new(KbdBacklight {
keyboard: self.keyboard.clone(),
})),
KDB_NAMESPACE => match self {
super::Client::Stopped { .. } => None,
super::Client::Started { devices, .. } => Some(Arc::new(KbdBacklight {
keyboards: devices.clone(),
})),
},
BACKLIGHT_CURRENT_NAMESPACE => Some(Arc::new(FsBacklight {
subsystem: "backlight".to_string(),
property: Property::Brightness,
Expand Down
Loading
Loading