# Copyright (C) 2023 Tomasz Kramkowski # SPDX-License-Identifier: MIT import argparse import math import sys from pathlib import Path from typing import Type, TypeVar T = TypeVar("T", bound="LogFloat") class LogFloat(float): @classmethod def from_val(cls: Type[T], val: int) -> T: return cls(math.log(val + 1)) @classmethod def from_pct(cls: Type[T], pct: float, log_max: "LogFloat") -> T: return cls(pct / 100.0 * log_max) def to_val(self) -> int: return round(math.e**self) - 1 def __add__(self, other: "LogFloat") -> "LogFloat": return LogFloat(super().__add__(other)) def _parse_limit(limit: str, log_max_brightness: LogFloat) -> int: if limit[-1] == "%": return LogFloat.from_pct(float(limit[:-1]), log_max_brightness).to_val() return int(limit) def main(argv: list[str] = sys.argv) -> int: ap = argparse.ArgumentParser(description="Adjust sysfs backlight with a log scale") ap.add_argument( "-m", "--min", help="An artificial minimum brightness (percentage or raw value) limit", default="0", ) ap.add_argument( "-M", "--max", help="An artificial maximum brightness (percentage or raw value) limit", ) ap.add_argument( "backlight", help="Path to sysfs backlight (e.g. /sys/class/backlight/amdgpu_bl0)", ) ap.add_argument( "adjustment", help="Percentage adjustment (e.g. +10 or -6.25) or absolute value (e.g. 50)", ) args = ap.parse_args(argv[1:]) backlight = Path(args.backlight) with open(backlight / "brightness") as f: brightness = int(f.read().rstrip()) log_brightness = LogFloat.from_val(brightness) with open(backlight / "max_brightness") as f: max_brightness = int(f.read().rstrip()) log_max_brightness = LogFloat.from_val(max_brightness) if args.adjustment[0] in {"-", "+"}: diff = LogFloat.from_pct(float(args.adjustment), log_max_brightness) new_brightness = (log_brightness + diff).to_val() if diff != 0 and new_brightness == brightness: new_brightness += int(math.copysign(1, diff)) else: new_brightness = LogFloat.from_pct( float(args.adjustment), log_max_brightness ).to_val() max_limit = max_brightness if args.max is not None: max_limit = _parse_limit(args.max, log_max_brightness) min_limit = _parse_limit(args.min, log_max_brightness) new_brightness = max(min_limit, min(new_brightness, max_limit)) with open(backlight / "brightness", "w") as f: f.write(str(new_brightness)) return 0