Skip to content
Snippets Groups Projects
Commit 4ea7c969 authored by Bastien Nocera's avatar Bastien Nocera
Browse files

power-profiles-daemon

parents
No related branches found
No related tags found
No related merge requests found
Pipeline #175262 passed
Showing
with 901 additions and 0 deletions
root = true
[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.md]
trim_trailing_whitespace = false
power-profiles-daemon
data/net.hadess.PowerProfiles.conf
image: fedora:rawhide
variables:
DEPENDENCIES: gcc gtk-doc pkgconfig(udev) pkgconfig(systemd) pkgconfig(gio-2.0) pkgconfig(gudev-1.0) systemd
meson git
build_stable:
before_script:
- dnf upgrade -y --nogpgcheck fedora-release fedora-repos*
- dnf update -y && dnf install -y $DEPENDENCIES
script:
- meson -Dgtk_doc=true -Dgtk-tests=true _build
- ninja -v -C _build
- ninja -v -C _build install
- ninja -v -C _build uninstall
- ninja -v -C _build dist
- meson test -C _build
This diff is collapsed.
NEWS 0 → 100644
0.1
---
This is the first version of power-profiles-daemon.
power-profiles-daemon
=====================
Makes power profiles handling available over D-Bus.
Installation
------------
```sh
$ meson _build -Dprefix=/usr
$ ninja -v -C _build install
```
It requires libgudev and systemd (>= 233 for the accelerometer quirks).
Introduction
------------
power-profiles-daemon offers to modify system behaviour based upon user-selected
power profiles. There are 3 different power profiles, a "balanced" default mode,
a "power-saver" mode, as well as a "performance" mode. The first 2 of those are
available on every system. The "performance" mode is only available on select
systems and is implemented by different "drivers" based on the system or
systems it targets.
In addition to those 2 or 3 modes (depending on the system), "actions" can be hooked
up to change the behaviour of a particular device. For example, this can be used
to disable the fast-charging for some USB devices when in power-saver mode.
GNOME's Settings and shell both include interfaces to select the current mode, but
they are also expected to adjust the behaviour of the desktop depending on the mode,
such as turning the screen off after inaction more aggressively when in power-saver
mode.
Note that power-profiles-daemon does not save the currently active profile across
system restarts and will always start with the "balanced" profile selected.
Debugging
---------
You can now check which mode is in use, and which ones are available by running:
```
gdbus introspect --system --dest net.hadess.PowerProfiles --object-path /net/hadess/PowerProfiles
```
If that doesn't work, please file an issue, make sure any running power-profiles-daemon
has been stopped:
`systemctl stop power-profiles-daemon.service`
and attach the output of:
`G_MESSAGES_DEBUG=all /usr/libexec/power-profiles-daemon`
running as ```root```.
References
----------
- [Use Low Power Mode to save battery life on your iPhone (iOS)](https://support.apple.com/en-us/HT205234)
- [lowPowerModeEnabled (iOS)](https://developer.apple.com/documentation/foundation/nsprocessinfo/1617047-lowpowermodeenabled?language=objc)
- [React to Low Power Mode on iPhones (iOS)](https://developer.apple.com/library/archive/documentation/Performance/Conceptual/EnergyGuide-iOS/LowPowerMode.html#//apple_ref/doc/uid/TP40015243-CH31)
- [[S]ettings that use less battery (Android)](https://support.google.com/android/answer/7664692?hl=en&visit_id=637297348326801871-2263015427&rd=1)
- [EnergySaverStatus Enum (Windows)](https://docs.microsoft.com/en-us/uwp/api/windows.system.power.energysaverstatus?view=winrt-19041)
data_conf = configuration_data()
data_conf.set('libexecdir', libexecdir)
configure_file(
input: 'power-profiles-daemon.service.in',
output: 'power-profiles-daemon.service',
configuration: data_conf,
install_dir: systemd_system_unit_dir,
)
configure_file(
input: 'net.hadess.PowerProfiles.conf.in',
output: 'net.hadess.PowerProfiles.conf',
configuration: data_conf,
install_dir: dbusconfdir
)
<?xml version="1.0" encoding="UTF-8"?> <!-- -*- XML -*- -->
<!DOCTYPE busconfig PUBLIC
"-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
<busconfig>
<!-- Only root can own the service -->
<policy user="root">
<allow own="net.hadess.PowerProfiles"/>
</policy>
<!-- Anyone can talk to the main interface -->
<policy context="default">
<allow send_destination="net.hadess.PowerProfiles" send_interface="net.hadess.PowerProfiles"/>
<allow send_destination="net.hadess.PowerProfiles" send_interface="org.freedesktop.DBus.Introspectable"/>
<allow send_destination="net.hadess.PowerProfiles" send_interface="org.freedesktop.DBus.Properties"/>
<allow send_destination="net.hadess.PowerProfiles" send_interface="org.freedesktop.DBus.Peer"/>
</policy>
</busconfig>
[Unit]
Description=Power Profiles daemon
[Service]
Type=dbus
BusName=net.hadess.PowerProfiles
ExecStart=@libexecdir@/power-profiles-daemon
#Uncomment this to enable debug
#Environment="G_MESSAGES_DEBUG=all"
# Lockdown
ProtectSystem=strict
ProtectControlGroups=true
ProtectHome=true
ProtectKernelModules=true
PrivateTmp=true
RestrictAddressFamilies=AF_UNIX AF_LOCAL AF_NETLINK
MemoryDenyWriteExecute=true
RestrictRealtime=true
content_files = files()
version_conf = configuration_data()
version_conf.set('VERSION', meson.project_version())
content_files += configure_file(
input: 'version.xml.in',
output: 'version.xml',
configuration: version_conf,
)
content_files += gnome.gdbus_codegen(
meson.project_name(),
sources: meson.source_root() / 'src' / 'net.hadess.PowerProfiles.xml',
interface_prefix: 'net.hadess',
namespace: 'PowerProfiles',
docbook: 'docs',
build_by_default: true,
)
gnome.gtkdoc(
meson.project_name(),
main_xml: meson.project_name() + '-docs.xml',
content_files: content_files,
src_dir: [
meson.source_root() /'src',
meson.build_root() / 'src',
],
ignore_headers: ['ppd-action.h', 'ppd-mode-driver.h'],
scan_args: ['--rebuild-sections'],
)
man1_dir = join_paths(get_option('prefix'), get_option('mandir'), 'man1')
xsltproc = find_program('xsltproc', required : true)
xsltproc_command = [
xsltproc,
'--nonet',
'--stringparam', 'man.output.quietly', '1',
'--stringparam', 'funcsynopsis.style', 'ansi',
'--stringparam', 'man.th.extra1.suppress', '1',
'--stringparam', 'man.authors.section.enabled', '0',
'--stringparam', 'man.copyright.section.enabled', '0',
'-o', '@OUTPUT@',
'http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl',
'@INPUT@',
]
<?xml version="1.0"?>
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" [
<!ENTITY version SYSTEM "version.xml">
]>
<book id="index" xmlns:xi="http://www.w3.org/2003/XInclude">
<bookinfo>
<title>Power Profiles daemon Reference Manual</title>
<releaseinfo>Version &version;</releaseinfo>
<authorgroup>
<author>
<firstname>Bastien</firstname>
<surname>Nocera</surname>
<affiliation>
<address>
<email>hadess@hadess.net</email>
</address>
</affiliation>
</author>
</authorgroup>
<copyright>
<year>2015</year>
<holder>Red Hat, Inc.</holder>
</copyright>
<legalnotice>
<para>
Permission is granted to copy, distribute and/or modify this
document under the terms of the <citetitle>GNU Free
Documentation License</citetitle>, Version 1.1 or any later
version published by the Free Software Foundation with no
Invariant Sections, no Front-Cover Texts, and no Back-Cover
Texts. You may obtain a copy of the <citetitle>GNU Free
Documentation License</citetitle> from the Free Software
Foundation by visiting <ulink type="http"
url="http://www.fsf.org">their Web site</ulink> or by writing
to:
<address>
The Free Software Foundation, Inc.,
<street>59 Temple Place</street> - Suite 330,
<city>Boston</city>, <state>MA</state> <postcode>02111-1307</postcode>,
<country>USA</country>
</address>
</para>
<para>
Many of the names used by companies to distinguish their
products and services are claimed as trademarks. Where those
names appear in any GNOME documentation, and those trademarks
are made aware to the members of the GNOME Documentation
Project, the names have been printed in caps or initial caps.
</para>
</legalnotice>
</bookinfo>
<reference id="ref-dbus">
<title>D-Bus API Reference</title>
<partintro>
<para>
This part documents the D-Bus interface used to access the
Power Profiles daemon.
</para>
</partintro>
<xi:include href="docs-net.hadess.PowerProfiles.xml"/>
</reference>
<index>
<title>Index</title>
</index>
<!-- License -->
<appendix id="license">
<title>License</title>
<para>
<programlisting><xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="../COPYING" parse="text"><xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
</para>
</appendix>
</book>
@VERSION@
project('power-profiles-daemon', [ 'c' ],
version: '0.1',
license: 'GPLv3+',
default_options: [
'buildtype=debugoptimized',
'warning_level=1',
'c_std=c99',
],
meson_version: '>= 0.54.0')
cc = meson.get_compiler('c')
common_cflags = cc.get_supported_arguments([
'-fgnu89-inline',
'-fvisibility=hidden',
'-std=gnu99',
'-Wall',
'-Wundef',
'-Wunused',
'-Wstrict-prototypes',
'-Werror-implicit-function-declaration',
'-Wno-pointer-sign',
'-Wshadow'
])
libexecdir = get_option('libexecdir')
bindir = get_option('bindir')
dbusconfdir = get_option('sysconfdir') / 'dbus-1' / 'system.d'
systemd_system_unit_dir = get_option('systemdsystemunitdir')
if systemd_system_unit_dir == 'auto'
systemd_dep = dependency('systemd')
systemd_system_unit_dir = systemd_dep.get_pkgconfig_variable('systemdsystemunitdir')
endif
gio_dep = dependency('gio-2.0')
gudev_dep = dependency('gudev-1.0', version: '>= 232')
gnome = import('gnome')
add_global_arguments('-D_GNU_SOURCE=1', language: 'c')
subdir('src')
subdir('data')
if get_option('gtk_doc')
# Make COPYING available in the build root for docs
configure_file(
input: 'COPYING',
output: 'COPYING',
copy: true,
)
subdir('docs')
endif
option('systemdsystemunitdir',
description: 'systemd unit directory',
type: 'string',
value: 'auto')
option('gtk_doc',
type: 'boolean',
value: false,
description: 'Build docs')
deps = [ gio_dep, gudev_dep ]
resources = gnome.compile_resources(
'power-profiles-daemon-resources', 'power-profiles-daemon.gresource.xml',
c_name: 'power_profiles_daemon',
source_dir: '.',
export: true
)
sources = [
'power-profiles-daemon.c',
'ppd-action.c',
'ppd-profile-driver.c',
'ppd-profile-driver-balanced.c',
'ppd-profile-driver-power-saver.c',
resources,
]
enums = 'ppd-enums'
sources += gnome.mkenums(
enums,
sources: 'ppd-profile.h',
c_template: enums + '.c.in',
h_template: enums + '.h.in'
)
executable('power-profiles-daemon',
sources,
dependencies: deps,
install: true,
install_dir: libexecdir
)
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node>
<!--
net.hadess.PowerProfiles:
@short_description: Power Profiles daemon
The power-profiles-daemon API is meant to be used by parts of the OS or
desktop environment to switch system power profiles based on user choice,
or user intent.
FIXME move more from README
The object path will be "/net/hadess/PowerProfiles".
-->
<interface name="net.hadess.PowerProfiles">
<!--
ActiveProfile:
The type of the currently active profile. It might not be the same as the
user selected profile, as it will change depending on hardware configuration.
-->
<property name="ActiveProfile" type="s" access="read"/>
<!--
SelectedProfile:
The type of the user-selected profile. It might not be the same as the
active profile, as it will change depending on hardware configuration.
-->
<property name="SelectedProfile" type="s" access="readwrite"/>
<!--
Inhibited:
This will be set if the user-selected power profile is unavailable, with
the value being used to identify the reason for unavailability. As new
reasons can be added, it is recommended that front-ends show a generic
reason if they do not recognise the value. Possible values are:
- "lap-detected" (the computer is sitting on the user's lap)
- "" (the empty string, if not inhibited)
-->
<property name="Inhibited" type="s" access="read"/>
<!--
Profiles:
An array of key-pair values representing each profile. The key named
"Driver" (s) identifies the power-profiles-daemon backend code used to
implement the profile.
The key named "Profile" (s) will be one of:
- "power-saver" (battery saving profile)
- "balanced" (the default profile)
- "performance" (a profile that does not care about noise or battery consumption)
Only one of each type of profile will be listed, with the daemon choosing the
more appropriate "driver" for each profile type.
-->
<property name="Profiles" type="aa{sv}" access="read"/>
</interface>
</node>
/*
* Copyright (c) 2014-2016, 2020 Bastien Nocera <hadess@hadess.net>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3 as published by
* the Free Software Foundation.
*
*/
#include "power-profiles-daemon-resources.h"
#include "power-profiles-daemon.h"
#include "ppd-profile-driver.h"
#include "ppd-action.h"
#include "ppd-enums.h"
#define POWER_PROFILES_DBUS_NAME "net.hadess.PowerProfiles"
#define POWER_PROFILES_DBUS_PATH "/net/hadess/PowerProfiles"
#define POWER_PROFILES_IFACE_NAME POWER_PROFILES_DBUS_NAME
typedef struct {
PpdProfileDriver *driver;
GList *actions; /* list of PpdActions for the profile */
} ProfileData;
typedef struct {
GMainLoop *loop;
// GUdevClient *client;
GDBusNodeInfo *introspection_data;
GDBusConnection *connection;
guint name_id;
int ret;
PpdProfile active_profile;
PpdProfile selected_profile;
ProfileData profile_data[NUM_PROFILES];
} PpdApp;
#define GET_DRIVER(p) (data->profile_data[p].driver)
#define ACTIVE_DRIVER (data->profile_data[data->active_profile].driver)
#define SELECTED_DRIVER (data->profile_data[data->selected_profile].driver)
/* profile drivers and actions */
// #include "ppd-action-mfi-fastcharge.h"
#include "ppd-profile-driver-balanced.h"
#include "ppd-profile-driver-power-saver.h"
typedef GType (*GTypeGetFunc) (void);
static GTypeGetFunc objects[] = {
ppd_profile_driver_balanced_get_type,
ppd_profile_driver_power_saver_get_type,
};
typedef enum {
PROP_ACTIVE_PROFILE = 1 << 0,
PROP_SELECTED_PROFILE = 1 << 1,
PROP_INHIBITED = 1 << 2,
PROP_PROFILES = 1 << 3,
} PropertiesMask;
#define PROP_ALL (PROP_ACTIVE_PROFILE | PROP_SELECTED_PROFILE | PROP_INHIBITED | PROP_PROFILES)
static const char *
profile_to_str (PpdProfile profile)
{
GEnumClass *klass = g_type_class_ref (PPD_TYPE_PROFILE);
GEnumValue *value = g_enum_get_value (klass, profile);
const gchar *name = value ? value->value_nick : "";
g_type_class_unref (klass);
return name;
}
static PpdProfile
profile_from_str (const char *str)
{
GEnumClass *klass = g_type_class_ref (PPD_TYPE_PROFILE);
GEnumValue *value = g_enum_get_value_by_nick (klass, str);
PpdProfile profile = value ? value->value : PPD_PROFILE_UNSET;
g_type_class_unref (klass);
return profile;
}
static const char *
get_active_profile (PpdApp *data)
{
return profile_to_str (data->active_profile);
}
static const char *
get_selected_profile (PpdApp *data)
{
return profile_to_str (data->selected_profile);
}
static const char *
get_inhibited (PpdApp *data)
{
PpdProfileDriver *driver;
const char *ret;
driver = data->profile_data[data->selected_profile].driver;
ret = ppd_profile_driver_get_inhibited (driver);
g_assert (ret != NULL);
return ret;
}
static GVariant *
get_profiles_variant (PpdApp *data)
{
GVariantBuilder builder;
guint i;
g_variant_builder_init (&builder, G_VARIANT_TYPE ("aa{sv}"));
for (i = 0; i < G_N_ELEMENTS(data->profile_data); i++) {
PpdProfileDriver *driver = data->profile_data[i].driver;
GVariantBuilder asv_builder;
if (driver == NULL)
continue;
g_variant_builder_init (&asv_builder, G_VARIANT_TYPE ("a{sv}"));
g_variant_builder_add (&asv_builder, "{sv}", "Driver",
g_variant_new_string (ppd_profile_driver_get_driver_name (driver)));
g_variant_builder_add (&asv_builder, "{sv}", "Profile",
g_variant_new_string (profile_to_str (ppd_profile_driver_get_profile (driver))));
g_variant_builder_add (&builder, "a{sv}", &asv_builder);
}
return g_variant_builder_end (&builder);
}
static void
send_dbus_event (PpdApp *data,
PropertiesMask mask)
{
GVariantBuilder props_builder;
GVariant *props_changed = NULL;
g_assert (data->connection);
if (mask == 0)
return;
g_assert ((mask & PROP_ALL) != 0);
g_variant_builder_init (&props_builder, G_VARIANT_TYPE ("a{sv}"));
if (mask & PROP_ACTIVE_PROFILE) {
g_variant_builder_add (&props_builder, "{sv}", "ActiveProfile",
g_variant_new_string (get_active_profile (data)));
}
if (mask & PROP_SELECTED_PROFILE) {
g_variant_builder_add (&props_builder, "{sv}", "SelectedProfile",
g_variant_new_string (get_selected_profile (data)));
}
if (mask & PROP_INHIBITED) {
g_variant_builder_add (&props_builder, "{sv}", "SelectedProfile",
g_variant_new_string (get_inhibited (data)));
}
if (mask & PROP_PROFILES) {
g_variant_builder_add (&props_builder, "{sv}", "Profiles",
get_profiles_variant (data));
}
props_changed = g_variant_new ("(s@a{sv}@as)", POWER_PROFILES_IFACE_NAME,
g_variant_builder_end (&props_builder),
g_variant_new_strv (NULL, 0));
g_dbus_connection_emit_signal (data->connection,
NULL,
POWER_PROFILES_DBUS_PATH,
"org.freedesktop.DBus.Properties",
"PropertiesChanged",
props_changed, NULL);
}
static gboolean
set_selected_profile (PpdApp *data,
const char *profile,
GError **error)
{
PpdProfile target_profile;
target_profile = profile_from_str (profile);
if (target_profile == PPD_PROFILE_UNSET) {
g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
"Invalid profile name '%s'", profile);
return FALSE;
}
if (target_profile == data->selected_profile) {
g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
"Profile '%s' already selected", profile);
return FALSE;
}
g_debug ("Transitioning from '%s' to '%s'",
profile_to_str (data->selected_profile), profile);
data->selected_profile = target_profile;
if (ppd_profile_driver_get_inhibited (SELECTED_DRIVER)) {
send_dbus_event (data, PROP_SELECTED_PROFILE);
g_debug ("Not transitioning to '%s' as inhibited", profile);
return TRUE;
}
//deactivate the current profile
//detactive the actions related to the current profile
//activate the target profile
//change the active profile
data->active_profile = target_profile;
send_dbus_event (data, PROP_ACTIVE_PROFILE | PROP_SELECTED_PROFILE);
return TRUE;
}
static GVariant *
handle_get_property (GDBusConnection *connection,
const gchar *sender,
const gchar *object_path,
const gchar *interface_name,
const gchar *property_name,
GError **error,
gpointer user_data)
{
PpdApp *data = user_data;
g_assert (data->connection);
if (g_strcmp0 (property_name, "ActiveProfile") == 0)
return g_variant_new_string (get_active_profile (data));
if (g_strcmp0 (property_name, "SelectedProfile") == 0)
return g_variant_new_string (get_selected_profile (data));
if (g_strcmp0 (property_name, "Inhibited") == 0)
return g_variant_new_string (get_inhibited (data));
if (g_strcmp0 (property_name, "Profiles") == 0)
return get_profiles_variant (data);
return NULL;
}
static gboolean
handle_set_property (GDBusConnection *connection,
const gchar *sender,
const gchar *object_path,
const gchar *interface_name,
const gchar *property_name,
GVariant *value,
GError **error,
gpointer user_data)
{
PpdApp *data = user_data;
const char *profile;
g_assert (data->connection);
if (g_strcmp0 (property_name, "SelectedProfile") != 0) {
g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
"No such property: %s", property_name);
return FALSE;
}
g_variant_get (value, "&s", &profile);
return set_selected_profile (data, profile, error);
}
static const GDBusInterfaceVTable interface_vtable =
{
NULL,
handle_get_property,
handle_set_property
};
static void
name_lost_handler (GDBusConnection *connection,
const gchar *name,
gpointer user_data)
{
g_debug ("power-profiles-daemon is already running, or it cannot own its D-Bus name. Verify installation.");
exit (0);
}
static void
bus_acquired_handler (GDBusConnection *connection,
const gchar *name,
gpointer user_data)
{
PpdApp *data = user_data;
g_dbus_connection_register_object (connection,
POWER_PROFILES_DBUS_PATH,
data->introspection_data->interfaces[0],
&interface_vtable,
data,
NULL,
NULL);
data->connection = g_object_ref (connection);
}
static gboolean
has_required_drivers (PpdApp *data)
{
if (!data->profile_data[PPD_PROFILE_BALANCED].driver ||
!G_IS_OBJECT (data->profile_data[PPD_PROFILE_BALANCED].driver) ||
!data->profile_data[PPD_PROFILE_POWER_SAVER].driver ||
!G_IS_OBJECT (data->profile_data[PPD_PROFILE_POWER_SAVER].driver)) {
return FALSE;
}
return TRUE;
}
static void
name_acquired_handler (GDBusConnection *connection,
const gchar *name,
gpointer user_data)
{
PpdApp *data = user_data;
guint i;
for (i = 0; i < G_N_ELEMENTS (objects); i++) {
GObject *object;
object = g_object_new (objects[i](), NULL);
if (PPD_IS_PROFILE_DRIVER (object)) {
PpdProfileDriver *driver = PPD_PROFILE_DRIVER (object);
PpdProfile profile;
g_message ("got driver %s", ppd_profile_driver_get_driver_name (driver));
profile = ppd_profile_driver_get_profile (driver);
if (profile == PPD_PROFILE_UNSET) {
g_warning ("Profile Driver '%s' implements invalid profile '%d'",
ppd_profile_driver_get_driver_name (driver),
profile);
g_object_unref (object);
continue;
}
/* FIXME implement selection for performance drivers */
data->profile_data[profile].driver = driver;
} else {
/* FIXME implement actions */
}
}
if (!has_required_drivers (data)) {
g_warning ("Some non-optional profile drivers are missing, programmer error");
goto bail;
}
send_dbus_event (data, PROP_ALL);
return;
bail:
data->ret = 0;
g_debug ("Exiting because some non recoverable error occurred during startup");
g_main_loop_quit (data->loop);
}
static gboolean
setup_dbus (PpdApp *data)
{
GBytes *bytes;
bytes = g_resources_lookup_data ("/net/hadess/PowerProfiles/net.hadess.PowerProfiles.xml",
G_RESOURCE_LOOKUP_FLAGS_NONE,
NULL);
data->introspection_data = g_dbus_node_info_new_for_xml (g_bytes_get_data (bytes, NULL), NULL);
g_bytes_unref (bytes);
g_assert (data->introspection_data != NULL);
data->name_id = g_bus_own_name (G_BUS_TYPE_SYSTEM,
POWER_PROFILES_DBUS_NAME,
G_BUS_NAME_OWNER_FLAGS_NONE,
bus_acquired_handler,
name_acquired_handler,
name_lost_handler,
data,
NULL);
return TRUE;
}
static void
free_app_data (PpdApp *data)
{
if (data == NULL)
return;
if (data->name_id != 0) {
g_bus_unown_name (data->name_id);
data->name_id = 0;
}
g_clear_pointer (&data->introspection_data, g_dbus_node_info_unref);
g_clear_object (&data->connection);
g_clear_pointer (&data->loop, g_main_loop_unref);
g_free (data);
}
int main (int argc, char **argv)
{
PpdApp *data;
int ret = 0;
data = g_new0 (PpdApp, 1);
/* Set up D-Bus */
setup_dbus (data);
data->loop = g_main_loop_new (NULL, TRUE);
g_main_loop_run (data->loop);
ret = data->ret;
free_app_data (data);
return ret;
}
<?xml version="1.0" encoding="UTF-8"?>
<gresources>
<gresource prefix="/net/hadess/PowerProfiles">
<file preprocess="xml-stripblanks">net.hadess.PowerProfiles.xml</file>
</gresource>
</gresources>
/*
* Copyright (c) 2020 Bastien Nocera <hadess@hadess.net>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3 as published by
* the Free Software Foundation.
*
*/
#pragma once
#include "ppd-profile.h"
#define NUM_PROFILES (PPD_PROFILE_PERFORMANCE + 1)
/*
* Copyright (c) 2020 Bastien Nocera <hadess@hadess.net>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3 as published by
* the Free Software Foundation.
*
*/
#include "ppd-action.h"
G_DEFINE_TYPE (PpdAction, ppd_action, G_TYPE_OBJECT)
static void
ppd_action_class_init (PpdActionClass *klass)
{
//FIXME define props
}
static void
ppd_action_init (PpdAction *self)
{
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment