roundabout,
created on Wednesday, 17 December 2025, 20:58:43 (1766005123),
received on Wednesday, 17 December 2025, 20:58:47 (1766005127)
Author identity: Vlad <vlad.muntoiu@gmail.com>
80b238b2f3109c009ee4b1876c62330271c1606e
applets/brightness/__init__.py
@@ -0,0 +1,106 @@
"""
Screen brightness control applet for the Panorama panel.
Copyright 2025, roundabout-host.com <vlad@roundabout-host.com>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public Licence as published by
the Free Software Foundation, either version 3 of the Licence, or
(at your option) any later version.
This program 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 Licence for more details.
You should have received a copy of the GNU General Public Licence
along with this program. If not, see <https://www.gnu.org/licenses/>.
"""
import os
import panorama_panel
import pydbus
import locale
from pathlib import Path
from pyudev import Context, Monitor, MonitorObserver
import gi
gi.require_version("Gtk", "4.0")
from gi.repository import Gtk, GLib, Gio
module_directory = Path(__file__).resolve().parent
locale.bindtextdomain("panorama-panel-file-listing", module_directory / "locale")
_ = lambda x: locale.dgettext("panorama-panel-file-listing", x)
def open_file_and_read_int(path: Path):
with open(path) as f:
return int(f.read().strip())
class ScreenBrightness(panorama_panel.Applet):
name = _("Brightness")
description = _("Control display brightness")
def __init__(self, orientation=Gtk.Orientation.HORIZONTAL, config=None):
super().__init__(orientation=orientation, config=config)
if config is None:
config = {}
self.icon = Gtk.Image.new_from_icon_name("display-brightness-symbolic")
self.icon.set_pixel_size(config.get("icon_size", 24))
self.button = Gtk.MenuButton(child=self.icon, has_frame=False)
self.append(self.button)
self.popover = Gtk.Popover()
self.box = Gtk.Box()
self.popover.set_child(self.box)
self.button.set_popover(self.popover)
self.bus = pydbus.SystemBus()
self.login1 = self.bus.get("org.freedesktop.login1", "/org/freedesktop/login1")
self.manager = self.bus.get("org.freedesktop.login1", "/org/freedesktop/login1")
self.session = self.bus.get("org.freedesktop.login1", self.manager.GetSessionByPID(os.getpid()))
self.backlights = [path for path in Path("/sys/class/backlight").iterdir()]
if not self.backlights:
self.button.hide()
self.adjustments = {}
self.sessions = self.manager.ListSessions()
self.udev_context = Context()
self.monitor = Monitor.from_netlink(self.udev_context)
self.monitor.filter_by(subsystem="backlight")
self.observer = MonitorObserver(self.monitor, callback=self.process_notify)
self.observer.start()
self.update_backlights()
def process_notify(self, device):
# Called when the brightness is updated in any way, even externally
path = Path("/sys/class/backlight") / device.sys_name
adjustment = self.adjustments.get(path)
value = open_file_and_read_int(path / "brightness")
if not adjustment:
return
def update():
adjustment.handler_block(adjustment.handler_id)
adjustment.set_value(value)
adjustment.handler_unblock(adjustment.handler_id)
return False
GLib.idle_add(update)
def update_backlights(self):
for backlight in self.backlights:
max_brightness = open_file_and_read_int(backlight / "max_brightness")
current_brightness = open_file_and_read_int(backlight / "brightness")
adjustment = Gtk.Adjustment(lower=0, upper=max_brightness, value=current_brightness)
adjustment.backlight = backlight
self.adjustments[backlight] = adjustment
adjustment.handler_id = adjustment.connect("value-changed", self.value_changed)
scale = Gtk.Scale(adjustment=adjustment, width_request=200)
self.box.append(scale)
def value_changed(self, adjustment, *args):
name = adjustment.backlight.name
self.session.SetBrightness("backlight", name, int(adjustment.get_value()))
def get_config(self):
return {"icon_size": self.icon.get_pixel_size()}
config.yaml
@@ -65,6 +65,8 @@ panels:
icon_size: 24
empty_icon_size: 16
right:
- ScreenBrightness:
icon_size: 24
- BatteryMonitor:
icon_size: 24
low_threshold: 0.15