Last active
March 18, 2025 08:23
-
-
Save michael-pisman/53cacea31f93c744ffc8afb583281cef to your computer and use it in GitHub Desktop.
A simple Qtile widget for controling display brightness with Xrandr
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
""" | |
Brightness Control Widget for Qtile | |
This module provides a reusable brightness control widget for the Qtile window manager. | |
It uses the 'xrandr' command to adjust the screen brightness and stores the brightness level | |
in a configuration file. This file is located under the user's home directory in a folder | |
named ".screenlayout". | |
Requirements: | |
- xrandr must be installed and available in the system path. | |
- Qtile and its widget base (libqtile.widget.base) must be installed. | |
Usage: | |
As a command-line tool: | |
python brightness.py [brightness_value|up|down] [display_name] | |
Examples: | |
python brightness.py up eDP # Increase brightness by 10% | |
python brightness.py 75 # Set brightness to 75% | |
python brightness.py # Print current brightness | |
As a widget in Qtile, instantiate Brightness with the desired parameters. | |
""" | |
import sys | |
from os import system, path | |
from libqtile.widget import base | |
# Configuration: Use the current user's home directory for configuration files. | |
DEFAULT_CONFIG_PATH = path.expanduser("~/.screenlayout/") | |
DEFAULT_DISPLAY_FILE = 'eDP' # Default display identifier | |
class Brightness(base.InLoopPollText): | |
""" | |
A Qtile widget to control and display screen brightness. | |
This widget reads the brightness value from a configuration file upon initialization, | |
updates the screen brightness using 'xrandr', and allows interactive adjustment via | |
mouse scroll events. The brightness is stored as an integer percentage (1-100). | |
Configurable defaults: | |
- format: Format string for displaying the brightness percentage. | |
- padding: Padding around the widget text. | |
- theme_path: Optional path for icon assets. | |
- display: Display identifier (e.g., 'eDP' or 'DisplayPort-1'). | |
- background: Background color for the widget. | |
""" | |
defaults = [ | |
('format', ' {percent}% ', 'Display format for brightness level'), | |
('padding', 3, 'Padding on left and right'), | |
('theme_path', None, 'Path for icon assets (optional)'), | |
('display', 'eDP', 'Display identifier'), | |
('background', None, 'Background color for widget') | |
] | |
def __init__(self, **config): | |
""" | |
Initialize the Brightness widget. | |
This sets up the widget by reading the current brightness, updating the screen | |
brightness accordingly, and registering callbacks for mouse scroll events. | |
""" | |
# Initialize the parent class with an empty text value and the given configuration. | |
super().__init__("", **config) | |
self.add_defaults(self.defaults) | |
# Read the initial brightness value from the configuration file. | |
self.brightness = self.get_brightness(self.display) | |
self.text = str(self.brightness) | |
# Apply the brightness setting to the display. | |
self.set_brightness(self.brightness, self.display) | |
# Register callbacks for mouse scroll events to adjust brightness. | |
self.add_callbacks({ | |
'Button4': lambda: self.set_brightness(self.brightness + 1, self.display), | |
'Button5': lambda: self.set_brightness(self.brightness - 1, self.display) | |
}) | |
def set_brightness(self, new_brightness, display): | |
""" | |
Set the screen brightness for the specified display. | |
Uses the 'xrandr' command to adjust brightness. The new brightness value (an integer | |
between 1 and 100) is also saved to a configuration file. | |
Parameters: | |
new_brightness (int): New brightness level (1-100). | |
display (str): The display identifier (e.g., 'eDP'). | |
""" | |
if 0 < new_brightness <= 100: | |
self.brightness = new_brightness | |
# xrandr expects a brightness value between 0 and 1. | |
system("xrandr --output {} --brightness {}".format(display, new_brightness / 100)) | |
# Save the new brightness to the configuration file. | |
config_file = path.join(DEFAULT_CONFIG_PATH, display) | |
with open(config_file, 'w+') as f: | |
f.write(str(new_brightness)) | |
else: | |
# Optionally, handle out-of-bound brightness values here. | |
pass | |
def get_brightness(self, display=DEFAULT_DISPLAY_FILE): | |
""" | |
Retrieve the current brightness level from the configuration file. | |
If the configuration file does not exist or contains invalid data, it is created or updated | |
with a default brightness value of 100. | |
Parameters: | |
display (str): The display identifier (e.g., 'eDP'). | |
Returns: | |
int: The current brightness level (1-100). | |
""" | |
config_file = path.join(DEFAULT_CONFIG_PATH, display) | |
default_brightness = 100 | |
if path.exists(config_file): | |
try: | |
with open(config_file, 'r') as f: | |
brightness = int(f.read()) | |
if 0 < brightness <= 100: | |
return brightness | |
except Exception: | |
# In case of an error, fall back to the default brightness. | |
pass | |
# Write the default brightness if the file is missing or invalid. | |
with open(config_file, 'w+') as f: | |
f.write(str(default_brightness)) | |
return default_brightness | |
def draw(self): | |
""" | |
Draw the widget on the Qtile bar. | |
Clears the current drawing area and renders the brightness text. | |
""" | |
# Clear the drawing area with the widget or bar background. | |
self.drawer.clear(self.background or self.bar.background) | |
# Use the parent class draw method to render the text. | |
base.InLoopPollText.draw(self) | |
# Finalize drawing. | |
self.drawer.draw(offsetx=self.offset, offsety=self.offsety, width=self.length) | |
def poll(self): | |
""" | |
Poll the brightness level for the widget display. | |
Returns: | |
str: A formatted string displaying the brightness percentage. | |
""" | |
try: | |
percent = self.brightness | |
except RuntimeError as e: | |
return 'Error: {}'.format(e) | |
return self.format.format(percent=percent) | |
def main(): | |
""" | |
Command-line interface for the brightness widget. | |
This function enables the script to be used from the command line to either | |
adjust or display the current brightness setting. | |
Usage: | |
python brightness.py [brightness_value|up|down] [display_name] | |
Examples: | |
python brightness.py up eDP # Increase brightness by 10% | |
python brightness.py 75 # Set brightness to 75% | |
python brightness.py # Print current brightness | |
""" | |
# Determine the display identifier; default is 'eDP'. | |
display = "eDP" | |
if len(sys.argv) == 3: | |
display = sys.argv[2] | |
widget = Brightness(display=display) | |
if len(sys.argv) >= 2: | |
cmd = sys.argv[1] | |
if cmd.isdigit(): | |
new_brightness = int(cmd) | |
elif cmd.lower() == "up": | |
new_brightness = widget.get_brightness() + 10 | |
elif cmd.lower() == "down": | |
new_brightness = widget.get_brightness() - 10 | |
elif cmd in ["eDP", "DisplayPort-1"]: | |
# If the command matches a display identifier, print its brightness. | |
print(widget.get_brightness(cmd)) | |
return | |
else: | |
print("ERROR: Invalid command") | |
return | |
widget.set_brightness(new_brightness, display) | |
else: | |
# If no command-line arguments are provided, print the current brightness. | |
print(widget.get_brightness()) | |
if __name__ == '__main__': | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment