aboutsummaryrefslogtreecommitdiffstats
path: root/brightness/__init__.py
blob: c5b497f8d0bebfe62c6c79b1b7eefc7ec2671246 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
# Copyright (C) 2023  Tomasz Kramkowski <tomasz@kramkow.ski>
# 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