Initial Fedora brightness automation setup
This commit is contained in:
14
bin/brightness-down-all
Executable file
14
bin/brightness-down-all
Executable file
@@ -0,0 +1,14 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
CONFIG="${BRIGHTNESS_AUTOMATION_CONFIG:-$HOME/.config/brightness-automation/env}"
|
||||
if [[ -f "$CONFIG" ]]; then
|
||||
# shellcheck disable=SC1090
|
||||
source "$CONFIG"
|
||||
fi
|
||||
|
||||
BACKLIGHT_DEVICE="${BRIGHTNESS_BACKLIGHT_DEVICE:-intel_backlight}"
|
||||
STEP="${BRIGHTNESS_STEP:-10}"
|
||||
|
||||
brightnessctl -q -d "$BACKLIGHT_DEVICE" set "${STEP}%-"
|
||||
"$HOME/.local/bin/brightness-osd" || true
|
||||
204
bin/brightness-osd
Executable file
204
bin/brightness-osd
Executable file
@@ -0,0 +1,204 @@
|
||||
#!/usr/bin/env python3
|
||||
import os
|
||||
import signal
|
||||
import sys
|
||||
import time
|
||||
|
||||
import gi
|
||||
|
||||
gi.require_version("Gtk", "4.0")
|
||||
gi.require_version("Adw", "1")
|
||||
from gi.repository import Adw, Gdk, GLib, Gtk
|
||||
|
||||
try:
|
||||
gi.require_version("Gtk4LayerShell", "1.0")
|
||||
from gi.repository import Gtk4LayerShell
|
||||
except (ImportError, ValueError):
|
||||
Gtk4LayerShell = None
|
||||
|
||||
|
||||
BACKLIGHT_PATH = os.environ.get(
|
||||
"BRIGHTNESS_OSD_BACKLIGHT", "/sys/class/backlight/intel_backlight"
|
||||
)
|
||||
PID_FILE = os.environ.get("BRIGHTNESS_OSD_PID", "/tmp/brightness-osd.pid")
|
||||
VALUE_FILE = os.environ.get("BRIGHTNESS_OSD_VALUE", "/tmp/brightness-osd.value")
|
||||
VISIBLE_MS = int(os.environ.get("BRIGHTNESS_OSD_VISIBLE_MS", "1400"))
|
||||
|
||||
|
||||
def read_percent():
|
||||
if len(sys.argv) > 1:
|
||||
return max(0, min(100, int(round(float(sys.argv[1])))))
|
||||
|
||||
with open(os.path.join(BACKLIGHT_PATH, "brightness"), encoding="utf-8") as handle:
|
||||
current = int(handle.read().strip())
|
||||
|
||||
with open(os.path.join(BACKLIGHT_PATH, "max_brightness"), encoding="utf-8") as handle:
|
||||
maximum = int(handle.read().strip())
|
||||
|
||||
return max(0, min(100, round(current * 100 / maximum)))
|
||||
|
||||
|
||||
def read_existing_pid():
|
||||
try:
|
||||
with open(PID_FILE, encoding="utf-8") as handle:
|
||||
return int(handle.read().strip())
|
||||
except (FileNotFoundError, ValueError):
|
||||
return None
|
||||
|
||||
|
||||
def process_exists(pid):
|
||||
try:
|
||||
os.kill(pid, 0)
|
||||
return True
|
||||
except ProcessLookupError:
|
||||
return False
|
||||
except PermissionError:
|
||||
return True
|
||||
|
||||
|
||||
def signal_existing(percent):
|
||||
pid = None
|
||||
for _attempt in range(5):
|
||||
pid = read_existing_pid()
|
||||
if pid and pid != os.getpid() and process_exists(pid):
|
||||
break
|
||||
time.sleep(0.03)
|
||||
else:
|
||||
return False
|
||||
|
||||
with open(VALUE_FILE, "w", encoding="utf-8") as handle:
|
||||
handle.write(str(percent))
|
||||
|
||||
try:
|
||||
os.kill(pid, signal.SIGUSR1)
|
||||
return True
|
||||
except ProcessLookupError:
|
||||
return False
|
||||
|
||||
|
||||
class BrightnessOsd(Adw.Application):
|
||||
def __init__(self, percent):
|
||||
super().__init__(application_id="local.brightness.osd")
|
||||
self.percent = percent
|
||||
self.label = None
|
||||
self.bar = None
|
||||
self.timeout_id = None
|
||||
|
||||
def update_percent(self, percent):
|
||||
self.percent = max(0, min(100, percent))
|
||||
|
||||
if self.label:
|
||||
self.label.set_label(f"{self.percent}%")
|
||||
if self.bar:
|
||||
self.bar.set_value(self.percent)
|
||||
|
||||
if self.timeout_id:
|
||||
GLib.source_remove(self.timeout_id)
|
||||
self.timeout_id = GLib.timeout_add(VISIBLE_MS, self.quit)
|
||||
|
||||
def handle_refresh(self, *_args):
|
||||
try:
|
||||
with open(VALUE_FILE, encoding="utf-8") as handle:
|
||||
percent = int(handle.read().strip())
|
||||
except (FileNotFoundError, ValueError):
|
||||
percent = read_percent()
|
||||
|
||||
GLib.idle_add(self.update_percent, percent)
|
||||
|
||||
def do_activate(self):
|
||||
with open(PID_FILE, "w", encoding="utf-8") as handle:
|
||||
handle.write(str(os.getpid()))
|
||||
|
||||
window = Gtk.ApplicationWindow(application=self)
|
||||
window.set_title("Brightness")
|
||||
window.set_decorated(False)
|
||||
window.set_resizable(False)
|
||||
window.set_default_size(190, 58)
|
||||
window.set_opacity(0.92)
|
||||
window.set_hide_on_close(True)
|
||||
|
||||
if Gtk4LayerShell is not None:
|
||||
Gtk4LayerShell.init_for_window(window)
|
||||
Gtk4LayerShell.set_layer(window, Gtk4LayerShell.Layer.OVERLAY)
|
||||
Gtk4LayerShell.set_anchor(window, Gtk4LayerShell.Edge.TOP, True)
|
||||
Gtk4LayerShell.set_margin(window, Gtk4LayerShell.Edge.TOP, 28)
|
||||
Gtk4LayerShell.set_keyboard_mode(window, Gtk4LayerShell.KeyboardMode.NONE)
|
||||
|
||||
css = Gtk.CssProvider()
|
||||
css.load_from_data(
|
||||
b"""
|
||||
window {
|
||||
background: transparent;
|
||||
}
|
||||
.osd {
|
||||
background: alpha(@window_fg_color, 0.88);
|
||||
color: @window_bg_color;
|
||||
border-radius: 15px;
|
||||
padding: 10px 14px;
|
||||
box-shadow: 0 10px 34px alpha(black, 0.34);
|
||||
}
|
||||
.osd image {
|
||||
color: @window_bg_color;
|
||||
}
|
||||
.percent {
|
||||
font-size: 15px;
|
||||
font-weight: 700;
|
||||
}
|
||||
levelbar trough {
|
||||
min-height: 6px;
|
||||
border-radius: 999px;
|
||||
background: alpha(@window_bg_color, 0.24);
|
||||
}
|
||||
levelbar block.filled {
|
||||
min-height: 6px;
|
||||
border-radius: 999px;
|
||||
background: @window_bg_color;
|
||||
}
|
||||
"""
|
||||
)
|
||||
Gtk.StyleContext.add_provider_for_display(
|
||||
Gdk.Display.get_default(), css, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION
|
||||
)
|
||||
|
||||
box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=10)
|
||||
box.add_css_class("osd")
|
||||
box.set_halign(Gtk.Align.CENTER)
|
||||
box.set_valign(Gtk.Align.START)
|
||||
box.set_margin_top(28)
|
||||
|
||||
icon = Gtk.Image.new_from_icon_name("display-brightness-symbolic")
|
||||
icon.set_pixel_size(22)
|
||||
|
||||
self.label = Gtk.Label(label=f"{self.percent}%")
|
||||
self.label.add_css_class("percent")
|
||||
self.label.set_width_chars(4)
|
||||
|
||||
self.bar = Gtk.LevelBar.new_for_interval(0, 100)
|
||||
self.bar.set_value(self.percent)
|
||||
self.bar.set_size_request(96, -1)
|
||||
self.bar.set_valign(Gtk.Align.CENTER)
|
||||
|
||||
box.append(icon)
|
||||
box.append(self.bar)
|
||||
box.append(self.label)
|
||||
window.set_child(box)
|
||||
|
||||
signal.signal(signal.SIGUSR1, self.handle_refresh)
|
||||
window.present()
|
||||
self.timeout_id = GLib.timeout_add(VISIBLE_MS, self.quit)
|
||||
|
||||
|
||||
def main():
|
||||
percent = read_percent()
|
||||
if signal_existing(percent):
|
||||
return 0
|
||||
|
||||
with open(PID_FILE, "w", encoding="utf-8") as handle:
|
||||
handle.write(str(os.getpid()))
|
||||
|
||||
app = BrightnessOsd(percent)
|
||||
return app.run([])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
65
bin/brightness-sync-hg342pcb
Executable file
65
bin/brightness-sync-hg342pcb
Executable file
@@ -0,0 +1,65 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
CONFIG="${BRIGHTNESS_AUTOMATION_CONFIG:-$HOME/.config/brightness-automation/env}"
|
||||
if [[ -f "$CONFIG" ]]; then
|
||||
# shellcheck disable=SC1090
|
||||
source "$CONFIG"
|
||||
fi
|
||||
|
||||
MODEL="${BRIGHTNESS_DDCUTIL_MODEL:-HG342PCB}"
|
||||
DISPLAY_NUM="${BRIGHTNESS_DDCUTIL_DISPLAY:-1}"
|
||||
BUS_NUM="${BRIGHTNESS_DDCUTIL_BUS:-16}"
|
||||
BACKLIGHT_PATH="${BRIGHTNESS_SYNC_BACKLIGHT:-/sys/class/backlight/intel_backlight}"
|
||||
INTERVAL="${BRIGHTNESS_SYNC_INTERVAL:-1}"
|
||||
MIN_PERCENT="${BRIGHTNESS_SYNC_MIN_PERCENT:-1}"
|
||||
|
||||
brightness_percent() {
|
||||
local current max percent
|
||||
|
||||
current="$(<"${BACKLIGHT_PATH}/brightness")"
|
||||
max="$(<"${BACKLIGHT_PATH}/max_brightness")"
|
||||
percent="$(( (current * 100 + max / 2) / max ))"
|
||||
|
||||
if (( percent < MIN_PERCENT )); then
|
||||
percent="$MIN_PERCENT"
|
||||
elif (( percent > 100 )); then
|
||||
percent=100
|
||||
fi
|
||||
|
||||
printf '%s\n' "$percent"
|
||||
}
|
||||
|
||||
run_ddcutil() {
|
||||
if sudo -n ddcutil --bus "$BUS_NUM" getvcp 10 >/dev/null 2>&1; then
|
||||
sudo -n ddcutil --bus "$BUS_NUM" "$@"
|
||||
return
|
||||
fi
|
||||
|
||||
if sudo -n ddcutil --display "$DISPLAY_NUM" getvcp 10 >/dev/null 2>&1; then
|
||||
sudo -n ddcutil --display "$DISPLAY_NUM" "$@"
|
||||
return
|
||||
fi
|
||||
|
||||
if sudo -n ddcutil --model "$MODEL" getvcp 10 >/dev/null 2>&1; then
|
||||
sudo -n ddcutil --model "$MODEL" "$@"
|
||||
return
|
||||
fi
|
||||
|
||||
echo "External ${MODEL} was not reachable via sudo -n ddcutil." >&2
|
||||
return 1
|
||||
}
|
||||
|
||||
last_percent=""
|
||||
|
||||
while true; do
|
||||
percent="$(brightness_percent)"
|
||||
|
||||
if [[ "$percent" != "$last_percent" ]]; then
|
||||
if run_ddcutil setvcp 10 "$percent" >/dev/null; then
|
||||
last_percent="$percent"
|
||||
fi
|
||||
fi
|
||||
|
||||
sleep "$INTERVAL"
|
||||
done
|
||||
14
bin/brightness-up-all
Executable file
14
bin/brightness-up-all
Executable file
@@ -0,0 +1,14 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
CONFIG="${BRIGHTNESS_AUTOMATION_CONFIG:-$HOME/.config/brightness-automation/env}"
|
||||
if [[ -f "$CONFIG" ]]; then
|
||||
# shellcheck disable=SC1090
|
||||
source "$CONFIG"
|
||||
fi
|
||||
|
||||
BACKLIGHT_DEVICE="${BRIGHTNESS_BACKLIGHT_DEVICE:-intel_backlight}"
|
||||
STEP="${BRIGHTNESS_STEP:-10}"
|
||||
|
||||
brightnessctl -q -d "$BACKLIGHT_DEVICE" set "+${STEP}%"
|
||||
"$HOME/.local/bin/brightness-osd" || true
|
||||
Reference in New Issue
Block a user