#!/usr/bin/env python3 import subprocess import json import sys from pathlib import Path def get_current_profile(): """Get the current power profile""" try: result = subprocess.run( ["powerprofilesctl", "get"], capture_output=True, text=True, timeout=5 ) if result.returncode == 0: return result.stdout.strip() except Exception as e: print(f"Error getting profile: {e}", file=sys.stderr) return "unknown" def get_available_profiles(): """Get list of available power profiles""" try: result = subprocess.run( ["powerprofilesctl", "list"], capture_output=True, text=True, timeout=5 ) if result.returncode == 0: profiles = [] for line in result.stdout.split('\n'): line = line.strip() if line and ':' in line and not line.startswith('Cpu') and not line.startswith('Platform') and not line.startswith('Degraded'): profile_name = line.split(':')[0].strip() if profile_name and not profile_name.startswith('*'): profiles.append(profile_name) elif profile_name.startswith('*'): profiles.append(profile_name[1:].strip()) return profiles except Exception as e: print(f"Error getting profiles: {e}", file=sys.stderr) return [] def set_profile(profile): """Set the power profile""" try: subprocess.run( ["powerprofilesctl", "set", profile], capture_output=True, timeout=5 ) except Exception as e: print(f"Error setting profile: {e}", file=sys.stderr) def write_menu_file(menu_path, profiles, current): """Write a GTK menu XML file for Waybar.""" items = [] if not profiles: items.append( " \n" " \n" " No profiles\n" " false\n" " \n" " \n" ) else: for profile in profiles: label = profile if profile == current: label = f"{profile} (current)" items.append( " \n" f" \n" f" {label}\n" " \n" " \n" ) content = ( "\n" "\n" " \n" + "".join(items) + " \n" "\n" ) try: menu_path.parent.mkdir(parents=True, exist_ok=True) menu_path.write_text(content) except Exception as e: print(f"Error writing menu file: {e}", file=sys.stderr) def format_output(profile): """Format output for waybar""" # Icons for each profile icons = { "performance": "⚡", "balanced": "⚖", "power-saver": "🔋" } icon = icons.get(profile, "⚡") output = { "text": f"{icon}", "alt": profile, "class": f"power-profile-{profile}", "tooltip": f"Current: {profile}" } return json.dumps(output) def main(): menu_path = Path("~/.config/waybar/modules/power_profiles_menu.xml").expanduser() if len(sys.argv) > 2 and sys.argv[1] == "--set": target = sys.argv[2] set_profile(target) current = get_current_profile() available = get_available_profiles() write_menu_file(menu_path, available, current) print(format_output(current)) return if len(sys.argv) > 1 and sys.argv[1] == "--next": # Cycle to next profile current = get_current_profile() available = get_available_profiles() write_menu_file(menu_path, available, current) if current in available and available: idx = available.index(current) next_profile = available[(idx + 1) % len(available)] set_profile(next_profile) print(format_output(next_profile)) else: print(format_output(current)) return # Just display current profile current = get_current_profile() available = get_available_profiles() write_menu_file(menu_path, available, current) print(format_output(current)) if __name__ == "__main__": main()