Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions ignis/dbus/org.freedesktop.UPower.PowerProfiles.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<node name="/">
<interface name="org.freedesktop.UPower.PowerProfiles">
<method name="HoldProfile">
<arg type="s" name="profile" direction="in">
</arg>
<arg type="s" name="reason" direction="in">
</arg>
<arg type="s" name="application_id" direction="in">
</arg>
<arg type="u" name="cookie" direction="out">
</arg>
</method>
<method name="ReleaseProfile">
<arg type="u" name="cookie" direction="in">
</arg>
</method>
<method name="SetActionEnabled">
<arg type="s" name="action" direction="in">
</arg>
<arg type="b" name="enabled" direction="in">
</arg>
</method>
<signal name="ProfileReleased">
<arg type="u" name="cookie">
</arg>
</signal>
<property type="s" name="ActiveProfile" access="readwrite">
</property>
<property type="s" name="PerformanceInhibited" access="read">
</property>
<property type="s" name="PerformanceDegraded" access="read">
</property>
<property type="aa{sv}" name="Profiles" access="read">
</property>
<property type="as" name="Actions" access="read">
</property>
<property type="aa{sv}" name="ActionsInfo" access="read">
</property>
<property type="aa{sv}" name="ActiveProfileHolds" access="read">
</property>
<property type="s" name="Version" access="read">
</property>
<property type="b" name="BatteryAware" access="readwrite">
</property>
</interface>
</node>
5 changes: 5 additions & 0 deletions ignis/services/power_profiles/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from .service import PowerProfilesService

__all__ = [
"PowerProfilesService",
]
133 changes: 133 additions & 0 deletions ignis/services/power_profiles/service.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
from __future__ import annotations
from ignis.base_service import BaseService
from ignis.dbus import DBusProxy
from ignis.gobject import IgnisProperty
from gi.repository import GLib # type: ignore
from ignis import utils


class PowerProfilesService(BaseService):
"""
A service for managing power profiles through the UPower DBus interface.

Example usage:

.. code-block:: python

from ignis.services.power_profiles import PowerProfilesService

power_profiles = PowerProfilesService.get_default()

print(power_profiles.active_profile)
power_profiles.active_profile = "performance"

for profile in power_profiles.profiles:
print(profile)

power_profiles.connect("notify::active-profile", lambda x, y: print(power_profiles.active_profile))
"""

def __init__(self) -> None:
super().__init__()

self._proxy = DBusProxy.new(
name="org.freedesktop.UPower.PowerProfiles",
object_path="/org/freedesktop/UPower/PowerProfiles",
interface_name="org.freedesktop.UPower.PowerProfiles",
info=utils.load_interface_xml("org.freedesktop.UPower.PowerProfiles"),
bus_type="system",
)

self._proxy.gproxy.connect("g-properties-changed", self.__on_properties_changed)

self._active_profile: str = self._proxy.ActiveProfile
self._profiles: list[str] = [p["Profile"] for p in self._proxy.Profiles]
self._cookie = -1

@IgnisProperty
def active_profile( # type: ignore
self,
) -> str:
"""
Current active power profile.

Should be either of:
- `performance`
- `balanced`
- `power-saver`
"""
return self._active_profile

@active_profile.setter
def active_profile(
self,
profile: str,
) -> None:
self._cookie = -1
self._proxy.ActiveProfile = GLib.Variant("s", profile)

def hold_profile(self, profile: str) -> None:
"""
This forces the passed profile (only `performance` or `power-saver`) to be activated until ignis exits,
:func:`~ignis.services.power_profiles.PowerProfilesService.release_profile` is called,
or the :attr:`~ignis.services.power_profiles.PowerProfilesService.active_profile` is changed manually.

Use if you need to ensure a specific profile is active for a certain amount of time or while
a specific task is being performed. This way the previous state will not have to be managed by you.
"""
if profile == "balanced":
raise ValueError(
"Cannot hold the balanced profile, only performance or power-saver."
)

if self._cookie != -1:
return

self._cookie = self._proxy.gproxy.HoldProfile(
"(sss)", profile, "", "com.github.linkfrg.ignis"
)

def release_profile(self) -> None:
"""
Release the hold on the profile
"""
if self._cookie == -1:
return

self._proxy.gproxy.ReleaseProfile("(u)", self._cookie)
self._cookie = -1

@IgnisProperty
def profiles(self) -> list[str]:
"""
List of available power profiles.

Possible values are:
- `performance`
- `balanced`
- `power-saver`
"""
return self._profiles

@IgnisProperty
def icon_name(self) -> str:
"""
The current icon name representing the active power profile.
"""
if self.active_profile == "performance":
return "power-profile-performance-symbolic"
if self.active_profile == "balanced":
return "power-profile-balanced-symbolic"
if self.active_profile == "power-saver":
return "power-profile-power-saver-symbolic"
return ""

def __on_properties_changed(self, _, properties: GLib.Variant, ignored):
prop_dict = properties.unpack()

if "ActiveProfile" in prop_dict:
self._active_profile = prop_dict["ActiveProfile"]
self.notify("active-profile")
if "Profiles" in prop_dict:
self._profiles = list(prop_dict["Profiles"].keys())
self.notify("profiles")