263 lines
7.9 KiB
Python
Executable File
263 lines
7.9 KiB
Python
Executable File
#!/usr/bin/python3
|
|
|
|
import signal
|
|
import subprocess
|
|
import sys
|
|
from gi.repository import Gio, GLib
|
|
|
|
VERSION = '0.10.1'
|
|
|
|
def usage_main():
|
|
print('Usage:')
|
|
print(' powerprofilesctl COMMAND [ARGS…]')
|
|
print('')
|
|
print('Commands:')
|
|
print(' help Print help')
|
|
print(' version Print version')
|
|
print(' get Print the currently active power profile')
|
|
print(' set Set the currently active power profile')
|
|
print(' list List available power profiles')
|
|
print(' list-holds List current power profile holds')
|
|
print(' launch Launch a command while holding a power profile')
|
|
print('')
|
|
print('Use “powerprofilesctl help COMMAND” to get detailed help.')
|
|
|
|
def usage_version():
|
|
print('Usage:')
|
|
print(' powerprofilesctl version')
|
|
print('')
|
|
print('Print version information and exit.')
|
|
|
|
def usage_get():
|
|
print('Usage:')
|
|
print(' powerprofilesctl get')
|
|
print('')
|
|
print('Print the currently active power profile.')
|
|
|
|
def usage_set():
|
|
print('Usage:')
|
|
print(' powerprofilesctl set PROFILE')
|
|
print('')
|
|
print('Set the currently active power profile. Must be one of the ')
|
|
print('available profiles.')
|
|
|
|
def usage_list():
|
|
print('Usage:')
|
|
print(' powerprofilesctl list')
|
|
print('')
|
|
print('List available power profiles.')
|
|
|
|
def usage_list_holds():
|
|
print('Usage:')
|
|
print(' powerprofilesctl list-holds')
|
|
print('')
|
|
print('List current power profile holds.')
|
|
|
|
def usage_launch():
|
|
print('Usage:')
|
|
print(' powerprofilesctl launch [COMMAND…]')
|
|
print('')
|
|
print('Launch a command while holding a power profile.')
|
|
print('')
|
|
print('Options:')
|
|
print(' -p, --profile=PROFILE The power profile to hold')
|
|
print(' -r, --reason=REASON The reason for the profile hold')
|
|
print(' -i, --appid=APP-ID The application ID for the profile hold')
|
|
print('')
|
|
print('Launch the command while holding a power profile, either performance, ')
|
|
print('or power-saver. By default, the profile hold is for the performance ')
|
|
print('profile, but it might not be available on all systems. See the list ')
|
|
print('command for a list of available profiles.')
|
|
|
|
def usage(_command=None):
|
|
if not _command:
|
|
usage_main()
|
|
elif _command == 'get':
|
|
usage_get()
|
|
elif _command == 'set':
|
|
usage_set()
|
|
elif _command == 'list':
|
|
usage_list()
|
|
elif _command == 'list-holds':
|
|
usage_list_holds()
|
|
elif _command == 'launch':
|
|
usage_launch()
|
|
elif _command == 'version':
|
|
usage_version()
|
|
else:
|
|
usage_main()
|
|
|
|
def version():
|
|
print (VERSION)
|
|
|
|
def get_proxy():
|
|
try:
|
|
bus = Gio.bus_get_sync(Gio.BusType.SYSTEM, None)
|
|
proxy = Gio.DBusProxy.new_sync(bus, Gio.DBusProxyFlags.NONE, None,
|
|
'net.hadess.PowerProfiles',
|
|
'/net/hadess/PowerProfiles',
|
|
'org.freedesktop.DBus.Properties', None)
|
|
except:
|
|
raise SystemError
|
|
return proxy
|
|
|
|
def _get():
|
|
proxy = get_proxy()
|
|
profile = proxy.Get('(ss)', 'net.hadess.PowerProfiles', 'ActiveProfile')
|
|
print(profile)
|
|
|
|
def _set(profile):
|
|
proxy = get_proxy()
|
|
proxy.Set('(ssv)',
|
|
'net.hadess.PowerProfiles',
|
|
'ActiveProfile',
|
|
GLib.Variant.new_string(profile))
|
|
|
|
def get_profiles_property(prop):
|
|
try:
|
|
proxy = get_proxy()
|
|
except:
|
|
raise SystemError
|
|
|
|
profiles = None
|
|
try:
|
|
profiles = proxy.Get('(ss)', 'net.hadess.PowerProfiles', prop)
|
|
except:
|
|
raise ReferenceError
|
|
else:
|
|
return profiles
|
|
|
|
def _list():
|
|
try:
|
|
profiles = get_profiles_property('Profiles')
|
|
reason = get_proxy().Get('(ss)', 'net.hadess.PowerProfiles', 'PerformanceDegraded')
|
|
degraded = (reason != '')
|
|
active = get_proxy().Get('(ss)', 'net.hadess.PowerProfiles', 'ActiveProfile')
|
|
except:
|
|
print("Couldn\'t get Profiles: ", sys.exc_info()[0])
|
|
raise SystemError
|
|
else:
|
|
index = 0
|
|
for profile in reversed(profiles):
|
|
if index > 0:
|
|
print('')
|
|
marker = '*' if profile['Profile'] == active else ' '
|
|
print(f'{marker} {profile["Profile"]}:')
|
|
print(' Driver: ', profile['Driver'])
|
|
if profile['Profile'] == 'performance':
|
|
print(' Degraded: ', f'yes ({reason})' if degraded else 'no')
|
|
index += 1
|
|
|
|
def _list_holds():
|
|
try:
|
|
holds = get_profiles_property('ActiveProfileHolds')
|
|
except:
|
|
# print("Couldn\'t get ActiveProfileHolds: ", sys.exc_info()[0])
|
|
raise SystemError
|
|
else:
|
|
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
|
|
|
|
def _launch(args, profile, appid, reason):
|
|
try:
|
|
bus = Gio.bus_get_sync(Gio.BusType.SYSTEM, None)
|
|
proxy = Gio.DBusProxy.new_sync(bus, Gio.DBusProxyFlags.NONE, None,
|
|
'net.hadess.PowerProfiles',
|
|
'/net/hadess/PowerProfiles',
|
|
'net.hadess.PowerProfiles', None)
|
|
except:
|
|
raise SystemError
|
|
|
|
cookie = proxy.HoldProfile('(sss)', profile, reason, appid)
|
|
|
|
# Kill child when we go away
|
|
def receive_signal(_signum, _stack):
|
|
launched_app.terminate()
|
|
signal.signal(signal.SIGTERM, receive_signal)
|
|
|
|
# print (f'Got {cookie} for {profile} hold')
|
|
with subprocess.Popen(args) as launched_app:
|
|
launched_app.wait()
|
|
proxy.ReleaseProfile('(u)', cookie)
|
|
|
|
def main(): # pylint: disable=too-many-branches, disable=too-many-statements
|
|
args = None
|
|
if len(sys.argv) == 1:
|
|
command = 'list'
|
|
elif len(sys.argv) >= 2:
|
|
command = sys.argv[1]
|
|
if command == '--help':
|
|
command = 'help'
|
|
if command == '--version':
|
|
command = 'version'
|
|
else:
|
|
args = sys.argv[2:]
|
|
|
|
if command == 'help':
|
|
if len(args) > 0:
|
|
usage(args[0])
|
|
else:
|
|
usage(None)
|
|
elif command == 'version':
|
|
version()
|
|
elif command == 'get':
|
|
_get()
|
|
elif command == 'set':
|
|
if len(args) != 1:
|
|
usage_set()
|
|
sys.exit(1)
|
|
_set(args[0])
|
|
elif command == 'list':
|
|
_list()
|
|
elif command == 'list-holds':
|
|
_list_holds()
|
|
elif command == 'launch':
|
|
if len(args) == 0:
|
|
sys.exit(0)
|
|
profile = None
|
|
reason = None
|
|
appid = None
|
|
while True:
|
|
if args[0] == '--':
|
|
args = args[1:]
|
|
break
|
|
if args[0][:9] == '--profile' or args[0] == '-p':
|
|
if args[0][:10] == '--profile=':
|
|
args = args[0].split('=') + args[1:]
|
|
profile = args[1]
|
|
args = args[2:]
|
|
continue
|
|
if args[0][:8] == '--reason' or args[0] == '-r':
|
|
if args[0][:9] == '--reason=':
|
|
args = args[0].split('=') + args[1:]
|
|
reason = args[1]
|
|
args = args[2:]
|
|
continue
|
|
if args[0][:7] == '--appid' or args[0] == '-i':
|
|
if args[0][:8] == '--appid=':
|
|
args = args[0].split('=') + args[1:]
|
|
appid = args[1]
|
|
args = args[2:]
|
|
continue
|
|
break
|
|
|
|
if len(args) < 1:
|
|
sys.exit(0)
|
|
if not appid:
|
|
appid = args[0]
|
|
if not reason:
|
|
reason = 'Running ' + appid
|
|
if not profile:
|
|
profile = 'performance'
|
|
_launch(args, profile, appid, reason)
|
|
|
|
if __name__ == '__main__':
|
|
main()
|