You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
166 lines
5.1 KiB
166 lines
5.1 KiB
3 years ago
|
# -*- coding: utf-8 -*-
|
||
|
#
|
||
|
# brightness.py
|
||
|
#
|
||
|
# Copyright © 2021 JezerM
|
||
|
#
|
||
|
# This file is part of Web Greeter.
|
||
|
#
|
||
|
# Web Greeter is free software; you can redistribute it and/or modify
|
||
|
# it under the terms of the GNU General Public License as published by
|
||
|
# the Free Software Foundation; either version 3 of the License, or
|
||
|
# (at your option) any later version.
|
||
|
#
|
||
|
# Web Greeter is distributed in the hope that it will be useful,
|
||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
# GNU General Public License for more details.
|
||
|
#
|
||
|
# The following additional terms are in effect as per Section 7 of the license:
|
||
|
#
|
||
|
# The preservation of all legal notices and author attributions in
|
||
|
# the material or in the Appropriate Legal Notices displayed
|
||
|
# by works containing it is required.
|
||
|
#
|
||
|
# You should have received a copy of the GNU General Public License
|
||
|
# along with Web Greeter; If not, see <http://www.gnu.org/licenses/>.
|
||
|
|
||
|
import os
|
||
|
import stat
|
||
|
import time
|
||
|
import pyinotify
|
||
|
from typing import List
|
||
|
from threading import Thread
|
||
|
import globals
|
||
|
from logger import logger
|
||
|
from config import web_greeter_config
|
||
|
|
||
|
sys_path = ["/sys/class/backlight/"]
|
||
|
|
||
|
def get_controllers() -> List[str]:
|
||
|
ctrls: List[str] = []
|
||
|
for dev in sys_path:
|
||
|
if os.path.exists(dev) and stat.S_ISDIR(os.stat(dev).st_mode):
|
||
|
drs = os.listdir(dev)
|
||
|
for name in drs:
|
||
|
ctrls.append(os.path.join(dev, name))
|
||
|
return ctrls
|
||
|
|
||
|
class EventHandler(pyinotify.ProcessEvent):
|
||
|
def process_IN_MODIFY(self, event):
|
||
|
if globals.greeter:
|
||
|
globals.greeter.greeter.brightness_update.emit()
|
||
|
|
||
|
|
||
|
# Behavior based on "acpilight"
|
||
|
# Copyright(c) 2016-2019 by wave++ "Yuri D'Elia" <wavexx@thregr.org>
|
||
|
# See https://gitlab.com/wavexx/acpilight
|
||
|
class BrightnessController:
|
||
|
|
||
|
_controllers: List[str] = []
|
||
|
_available: bool = False
|
||
|
_brightness_path: str
|
||
|
_max_brightness_path: str
|
||
|
steps: int
|
||
|
delay: int
|
||
|
_brightness: int
|
||
|
_max_brightness: int = -1
|
||
|
|
||
|
def __init__(self):
|
||
|
self._controllers = get_controllers()
|
||
|
if (len(self._controllers) == 0 or
|
||
|
self._controllers[0] == None or
|
||
|
web_greeter_config["config"]["features"]["backlight"]["enabled"] == False):
|
||
|
self._available = False
|
||
|
return
|
||
|
b_path = self._controllers[0]
|
||
|
self._available = True
|
||
|
self._brightness_path = os.path.join(b_path, "brightness")
|
||
|
self._max_brightness_path = os.path.join(b_path, "max_brightness")
|
||
|
|
||
|
with open(self._max_brightness_path, "r") as f:
|
||
|
self._max_brightness = int(f.read())
|
||
|
|
||
|
steps = web_greeter_config["config"]["features"]["backlight"]["steps"]
|
||
|
self.steps = 1 if steps <= 1 else steps
|
||
|
self.delay = 200
|
||
|
self.watch_brightness()
|
||
|
|
||
|
def _watch(self):
|
||
|
wm = pyinotify.WatchManager()
|
||
|
handler = EventHandler()
|
||
|
wm.add_watch(self._brightness_path, pyinotify.IN_MODIFY)
|
||
|
|
||
|
notifier = pyinotify.Notifier(wm, handler)
|
||
|
|
||
|
notifier.loop()
|
||
|
|
||
|
def watch_brightness(self):
|
||
|
if not self._available:
|
||
|
return
|
||
|
thread = Thread(target = self._watch)
|
||
|
thread.daemon = True
|
||
|
thread.start()
|
||
|
|
||
|
@property
|
||
|
def max_brightness(self) -> int:
|
||
|
return self._max_brightness
|
||
|
|
||
|
@property
|
||
|
def real_brightness(self) -> int:
|
||
|
if not self._available: return -1
|
||
|
try:
|
||
|
with open(self._brightness_path, "r") as f:
|
||
|
return int(f.read())
|
||
|
except OSError:
|
||
|
logger.error("Couldn't read from \"" + self._brightness_path + "\"")
|
||
|
return -1
|
||
|
|
||
|
@real_brightness.setter
|
||
|
def real_brightness(self, v: int):
|
||
|
if not self._available: return
|
||
|
if v > self.max_brightness: v = self.max_brightness
|
||
|
elif v <= 0: v = 0
|
||
|
|
||
|
if not os.path.exists(self._brightness_path): return
|
||
|
|
||
|
try:
|
||
|
with open(self._brightness_path, "w") as f:
|
||
|
f.write(str(round(v)))
|
||
|
except OSError:
|
||
|
logger.error("Couldn't write to \"" + self._brightness_path + "\"")
|
||
|
|
||
|
@property
|
||
|
def brightness(self) -> int:
|
||
|
if not self._available: return -1
|
||
|
return round(self.real_brightness * 100 / self.max_brightness)
|
||
|
|
||
|
@brightness.setter
|
||
|
def brightness(self, v: int):
|
||
|
self.real_brightness = round(v * self.max_brightness / 100)
|
||
|
|
||
|
def _set_brightness(self, value: int):
|
||
|
if not self._available: return
|
||
|
steps = self.steps or 1
|
||
|
sleep = self.delay / steps
|
||
|
current = self.brightness
|
||
|
|
||
|
if steps <= 1:
|
||
|
self.brightness = value
|
||
|
return
|
||
|
|
||
|
for i in range(steps + 1):
|
||
|
time.sleep(sleep / 1000)
|
||
|
brigh = current + ((value - current) * i) / steps
|
||
|
self.brightness = round(brigh)
|
||
|
|
||
|
def set_brightness(self, value: int):
|
||
|
thread = Thread(target = self._set_brightness, args = (value,))
|
||
|
thread.start()
|
||
|
|
||
|
def inc_brightness(self, value: int):
|
||
|
self.set_brightness(self.brightness + value)
|
||
|
|
||
|
def dec_brightness(self, value: int):
|
||
|
self.set_brightness(self.brightness - value)
|