%PDF- %PDF-
Direktori : /bin/ |
Current File : //bin/powerprofilesctl |
#! /usr/bin/python3 import argparse import os import signal import subprocess import sys from gi.repository import Gio, GLib PP_NAME = "org.freedesktop.UPower.PowerProfiles" PP_PATH = "/org/freedesktop/UPower/PowerProfiles" PP_IFACE = "org.freedesktop.UPower.PowerProfiles" PROPERTIES_IFACE = "org.freedesktop.DBus.Properties" def get_proxy(): bus = Gio.bus_get_sync(Gio.BusType.SYSTEM, None) return Gio.DBusProxy.new_sync( bus, Gio.DBusProxyFlags.NONE, None, PP_NAME, PP_PATH, PROPERTIES_IFACE, None ) def command(func): def wrapper(*args, **kwargs): try: func(*args, **kwargs) except GLib.Error as error: sys.stderr.write( f"Failed to communicate with power-profiles-daemon: {error}\n" ) sys.exit(1) except ValueError as error: sys.stderr.write(f"Error: {error}\n") sys.exit(1) return wrapper @command def _version(_args): client_version = "0.21" try: proxy = get_proxy() daemon_ver = proxy.Get("(ss)", PP_IFACE, "Version") except GLib.Error: daemon_ver = "unknown" print(f"client: {client_version}\ndaemon: {daemon_ver}") @command def _get(_args): proxy = get_proxy() profile = proxy.Get("(ss)", PP_IFACE, "ActiveProfile") print(profile) @command def _set(args): proxy = get_proxy() proxy.Set( "(ssv)", PP_IFACE, "ActiveProfile", GLib.Variant.new_string(args.profile[0]) ) def get_profiles_property(prop): proxy = get_proxy() return proxy.Get("(ss)", PP_IFACE, prop) @command def _list(_args): profiles = get_profiles_property("Profiles") reason = get_proxy().Get("(ss)", PP_IFACE, "PerformanceDegraded") degraded = reason != "" active = get_proxy().Get("(ss)", PP_IFACE, "ActiveProfile") index = 0 for profile in reversed(profiles): if index > 0: print("") marker = "*" if profile["Profile"] == active else " " print(f'{marker} {profile["Profile"]}:') for driver in ["CpuDriver", "PlatformDriver"]: if driver not in profile: continue value = profile[driver] print(f" {driver}:\t{value}") if profile["Profile"] == "performance": print(" Degraded: ", f"yes ({reason})" if degraded else "no") index += 1 @command def _list_holds(_args): holds = get_profiles_property("ActiveProfileHolds") index = 0 for hold in holds: if index > 0: print("") print("Hold:") print(" Profile: ", hold["Profile"]) print(" Application ID: ", hold["ApplicationId"]) print(" Reason: ", hold["Reason"]) index += 1 @command def _launch(args): reason = args.reason profile = args.profile appid = args.appid if not args.arguments: raise ValueError("No command to launch") if not args.appid: appid = args.arguments[0] if not profile: profile = "performance" if not reason: reason = f"Running {args.appid}" ret = 0 bus = Gio.bus_get_sync(Gio.BusType.SYSTEM, None) proxy = Gio.DBusProxy.new_sync( bus, Gio.DBusProxyFlags.NONE, None, PP_NAME, PP_PATH, PP_IFACE, None ) cookie = proxy.HoldProfile("(sss)", profile, reason, appid) # print (f'Got {cookie} for {profile} hold') with subprocess.Popen(args.arguments) as launched_app: # Redirect the same signal to the child def receive_signal(signum, _stack): launched_app.send_signal(signum) redirected_signals = [ signal.SIGTERM, signal.SIGINT, signal.SIGABRT, ] for sig in redirected_signals: signal.signal(sig, receive_signal) try: launched_app.wait() ret = launched_app.returncode except KeyboardInterrupt: ret = launched_app.returncode for sig in redirected_signals: signal.signal(sig, signal.SIG_DFL) proxy.ReleaseProfile("(u)", cookie) if ret < 0: # Use standard POSIX signal exit code. os.kill(os.getpid(), -ret) return sys.exit(ret) def get_parser(): parser = argparse.ArgumentParser( epilog="Use “powerprofilesctl COMMAND --help” to get detailed help for individual commands", ) subparsers = parser.add_subparsers(help="Individual command help", dest="command") parser_list = subparsers.add_parser("list", help="List available power profiles") parser_list.set_defaults(func=_list) parser_list_holds = subparsers.add_parser( "list-holds", help="List current power profile holds" ) parser_list_holds.set_defaults(func=_list_holds) parser_get = subparsers.add_parser( "get", help="Print the currently active power profile" ) parser_get.set_defaults(func=_get) parser_set = subparsers.add_parser( "set", help="Set the currently active power profile" ) parser_set.add_argument( "profile", nargs=1, help="Profile to use for set command", ) parser_set.set_defaults(func=_set) parser_launch = subparsers.add_parser( "launch", help="Launch a command while holding a power profile", description="Launch the command while holding a power profile," "either performance, or power-saver. By default, the profile hold " "is for the performance profile, but it might not be available on " "all systems. See the list command for a list of available profiles.", ) parser_launch.add_argument( "arguments", nargs="*", help="Command to launch", ) parser_launch.add_argument( "--profile", "-p", required=False, help="Profile to use for launch command" ) parser_launch.add_argument( "--reason", "-r", required=False, help="Reason to use for launch command" ) parser_launch.add_argument( "--appid", "-i", required=False, help="AppId to use for launch command" ) parser_launch.set_defaults(func=_launch) parser_version = subparsers.add_parser( "version", help="Print version information and exit" ) parser_version.set_defaults(func=_version) if not os.getenv("PPD_COMPLETIONS_GENERATION"): return parser try: import shtab # pylint: disable=import-outside-toplevel shtab.add_argument_to(parser, ["--print-completion"]) # magic! except ImportError: pass return parser def check_unknown_args(args, unknown_args, cmd): if cmd != "launch": return False for idx, unknown_arg in enumerate(unknown_args): arg = args[idx] if arg == cmd: return True if unknown_arg == arg: return False return True def main(): parser = get_parser() args, unknown = parser.parse_known_args() # default behavior is to run list if no command is given if not args.command: args.func = _list if check_unknown_args(sys.argv[1:], unknown, args.command): args.arguments += unknown unknown = [] if unknown: msg = argparse._("unrecognized arguments: %s") parser.error(msg % " ".join(unknown)) args.func(args) if __name__ == "__main__": main()