summaryrefslogtreecommitdiff
path: root/lib/powerprofiles
diff options
context:
space:
mode:
Diffstat (limited to 'lib/powerprofiles')
-rw-r--r--lib/powerprofiles/cli.vala80
-rw-r--r--lib/powerprofiles/config.vala.in6
-rw-r--r--lib/powerprofiles/meson.build93
-rw-r--r--lib/powerprofiles/meson_options.txt11
-rw-r--r--lib/powerprofiles/power-profiles.vala205
-rw-r--r--lib/powerprofiles/version1
6 files changed, 396 insertions, 0 deletions
diff --git a/lib/powerprofiles/cli.vala b/lib/powerprofiles/cli.vala
new file mode 100644
index 0000000..7be01d2
--- /dev/null
+++ b/lib/powerprofiles/cli.vala
@@ -0,0 +1,80 @@
+static bool help;
+static bool version;
+static bool daemonize;
+static bool list;
+static string set;
+
+const OptionEntry[] options = {
+ { "version", 'v', OptionFlags.NONE, OptionArg.NONE, ref version, null, null },
+ { "help", 'h', OptionFlags.NONE, OptionArg.NONE, ref help, null, null },
+ { "daemonize", 'd', OptionFlags.NONE, OptionArg.NONE, ref daemonize, null, null },
+ { "list", 'l', OptionFlags.NONE, OptionArg.NONE, ref list, null, null },
+ { "set", 's', OptionFlags.NONE, OptionArg.STRING, ref set, null, null },
+ { null },
+};
+
+int main(string[] argv) {
+ try {
+ var opts = new OptionContext();
+ opts.add_main_entries(options, null);
+ opts.set_help_enabled(false);
+ opts.set_ignore_unknown_options(false);
+ opts.parse(ref argv);
+ } catch (OptionError err) {
+ printerr (err.message);
+ return 1;
+ }
+
+ if (help) {
+ print("Usage:\n");
+ print(" %s [flags]\n\n", argv[0]);
+ print("Flags:\n");
+ print(" -h, --help Print this help and exit\n");
+ print(" -v, --version Print version number and exit\n");
+ print(" -d, --daemonize Monitor for changes\n");
+ print(" -l, --list List available profiles\n");
+ return 0;
+ }
+
+ if (version) {
+ print(AstalPowerProfiles.VERSION);
+ return 0;
+ }
+
+ var profiles = AstalPowerProfiles.get_default();
+ if (set != null) {
+ profiles.active_profile = set;
+ }
+
+ else if (list) {
+ foreach (var p in profiles.profiles) {
+ print("%s\n", p.profile);
+ }
+ return 0;
+ }
+
+ if (daemonize) {
+ var loop = new MainLoop();
+
+ stdout.printf("%s\n", profiles.to_json_string());
+ stdout.flush();
+
+ profiles.notify.connect(() => {
+ stdout.printf("%s\n", profiles.to_json_string());
+ stdout.flush();
+ });
+
+ profiles.profile_released.connect(() => {
+ stdout.printf("%s\n", profiles.to_json_string());
+ stdout.flush();
+ });
+
+ loop.run();
+ }
+
+ if (set == null && !daemonize) {
+ stdout.printf("%s\n", profiles.to_json_string());
+ }
+
+ return 0;
+}
diff --git a/lib/powerprofiles/config.vala.in b/lib/powerprofiles/config.vala.in
new file mode 100644
index 0000000..79034f1
--- /dev/null
+++ b/lib/powerprofiles/config.vala.in
@@ -0,0 +1,6 @@
+namespace AstalPowerProfiles {
+ public const int MAJOR_VERSION = @MAJOR_VERSION@;
+ public const int MINOR_VERSION = @MINOR_VERSION@;
+ public const int MICRO_VERSION = @MICRO_VERSION@;
+ public const string VERSION = "@VERSION@";
+}
diff --git a/lib/powerprofiles/meson.build b/lib/powerprofiles/meson.build
new file mode 100644
index 0000000..d0fe78f
--- /dev/null
+++ b/lib/powerprofiles/meson.build
@@ -0,0 +1,93 @@
+project(
+ 'astal-power-profiles',
+ 'vala',
+ 'c',
+ version: run_command('cat', join_paths(meson.project_source_root(), 'version')).stdout().strip(),
+ meson_version: '>= 0.62.0',
+ default_options: [
+ 'warning_level=2',
+ 'werror=false',
+ 'c_std=gnu11',
+ ],
+)
+
+assert(
+ get_option('lib') or get_option('cli'),
+ 'Either lib or cli option must be set to true.',
+)
+
+version_split = meson.project_version().split('.')
+api_version = version_split[0] + '.' + version_split[1]
+gir = 'AstalPowerProfiles-' + api_version + '.gir'
+typelib = 'AstalPowerProfiles-' + api_version + '.typelib'
+
+config = configure_file(
+ input: 'config.vala.in',
+ output: 'config.vala',
+ configuration: {
+ 'VERSION': meson.project_version(),
+ 'MAJOR_VERSION': version_split[0],
+ 'MINOR_VERSION': version_split[1],
+ 'MICRO_VERSION': version_split[2],
+ },
+)
+
+deps = [
+ dependency('glib-2.0'),
+ dependency('gobject-2.0'),
+ dependency('gio-2.0'),
+ dependency('json-glib-1.0'),
+]
+
+sources = [
+ config,
+ 'power-profiles.vala',
+]
+
+if get_option('lib')
+ lib = library(
+ meson.project_name(),
+ sources,
+ dependencies: deps,
+ vala_header: meson.project_name() + '.h',
+ vala_vapi: meson.project_name() + '-' + api_version + '.vapi',
+ vala_gir: gir,
+ version: meson.project_version(),
+ install: true,
+ install_dir: [true, true, true, true],
+ )
+
+ import('pkgconfig').generate(
+ lib,
+ name: meson.project_name(),
+ filebase: meson.project_name() + '-' + api_version,
+ version: meson.project_version(),
+ subdirs: meson.project_name(),
+ requires: deps,
+ install_dir: get_option('libdir') / 'pkgconfig',
+ )
+
+ custom_target(
+ typelib,
+ command: [
+ find_program('g-ir-compiler'),
+ '--output', '@OUTPUT@',
+ '--shared-library', get_option('prefix') / get_option('libdir') / '@PLAINNAME@',
+ meson.current_build_dir() / gir,
+ ],
+ input: lib,
+ output: typelib,
+ depends: lib,
+ install: true,
+ install_dir: get_option('libdir') / 'girepository-1.0',
+ )
+endif
+
+if get_option('cli')
+ executable(
+ meson.project_name(),
+ ['cli.vala', sources],
+ dependencies: deps,
+ install: true,
+ )
+endif
diff --git a/lib/powerprofiles/meson_options.txt b/lib/powerprofiles/meson_options.txt
new file mode 100644
index 0000000..f110242
--- /dev/null
+++ b/lib/powerprofiles/meson_options.txt
@@ -0,0 +1,11 @@
+option(
+ 'lib',
+ type: 'boolean',
+ value: true,
+)
+
+option(
+ 'cli',
+ type: 'boolean',
+ value: true,
+)
diff --git a/lib/powerprofiles/power-profiles.vala b/lib/powerprofiles/power-profiles.vala
new file mode 100644
index 0000000..ab98505
--- /dev/null
+++ b/lib/powerprofiles/power-profiles.vala
@@ -0,0 +1,205 @@
+namespace AstalPowerProfiles {
+[DBus (name = "org.freedesktop.UPower.PowerProfiles")]
+private interface IPowerProfiles : DBusProxy {
+ public abstract string[] actions { owned get; }
+ public abstract string active_profile { owned get; set; }
+ public abstract HashTable<string, Variant>[] active_profile_holds { owned get; }
+ public abstract string performance_degraded { owned get; }
+ public abstract string performance_inhibited { owned get; }
+ public abstract HashTable<string, Variant>[] profiles { owned get; }
+ public abstract string version { owned get; }
+
+ public signal void profile_released (uint cookie);
+
+ public abstract uint hold_profile(string profile, string reason, string application_id) throws Error;
+ public abstract void release_profile(uint cookie) throws Error;
+}
+
+public PowerProfiles get_default() {
+ return PowerProfiles.get_default();
+}
+
+public class PowerProfiles : Object {
+ private static PowerProfiles instance;
+ public static PowerProfiles get_default() {
+ if (instance == null)
+ instance = new PowerProfiles();
+
+ return instance;
+ }
+
+ private IPowerProfiles proxy;
+
+ construct {
+ try {
+ proxy = Bus.get_proxy_sync(
+ GLib.BusType.SYSTEM,
+ "org.freedesktop.UPower.PowerProfiles",
+ "/org/freedesktop/UPower/PowerProfiles"
+ );
+
+ proxy.profile_released.connect((cookie) => profile_released(cookie));
+ proxy.g_properties_changed.connect((props) => {
+ var map = (HashTable<string, Variant>)props;
+ foreach (var key in map.get_keys()) {
+ notify_property(kebab_case(key));
+ if (key == "ActiveProfile")
+ notify_property("icon-name");
+ }
+ });
+ } catch (Error error){
+ critical(error.message);
+ }
+ }
+
+ public string active_profile {
+ owned get { return proxy.active_profile; }
+ set { proxy.active_profile = value; }
+ }
+
+ public string icon_name {
+ owned get { return @"power-profile-$active_profile-symbolic"; }
+ }
+
+ public string[] actions {
+ owned get { return proxy.actions.copy(); }
+ }
+
+ public Hold[] active_profile_holds {
+ owned get {
+ Hold[] holds = new Hold[proxy.active_profile_holds.length];
+ for (var i = 0; i < proxy.active_profile_holds.length; ++i) {
+ var hold = proxy.active_profile_holds[i];
+ holds[i] = Hold() {
+ application_id = hold.get("ApplicationId").get_string(),
+ profile = hold.get("Profile").get_string(),
+ reason = hold.get("Reason").get_string()
+ };
+ }
+ return holds;
+ }
+ }
+
+ public string performance_degraded {
+ owned get { return proxy.performance_degraded; }
+ }
+
+ public string performance_inhibited {
+ owned get { return proxy.performance_degraded; }
+ }
+
+ public Profile[] profiles {
+ owned get {
+ Profile[] profs = new Profile[proxy.profiles.length];
+ for (var i = 0; i < proxy.profiles.length; ++i) {
+ var prof = proxy.profiles[i];
+ profs[i] = Profile() {
+ profile = prof.get("Profile").get_string(),
+ cpu_driver = prof.get("CpuDriver").get_string(),
+ platform_driver = prof.get("PlatformDriver").get_string(),
+ driver = prof.get("Driver").get_string()
+ };
+ }
+ return profs;
+ }
+ }
+
+ public string version {
+ owned get { return proxy.version; }
+ }
+
+ public signal void profile_released (uint cookie);
+
+ public int hold_profile(string profile, string reason, string application_id) {
+ try {
+ return (int)proxy.hold_profile(profile, reason, application_id);
+ } catch (Error error) {
+ critical(error.message);
+ return -1;
+ }
+ }
+
+ public void release_profile(uint cookie) {
+ try {
+ proxy.release_profile(cookie);
+ } catch (Error error) {
+ critical(error.message);
+ }
+ }
+
+ public string to_json_string() {
+ var acts = new Json.Builder().begin_array();
+ foreach (var action in actions) {
+ acts.add_string_value(action);
+ }
+
+ var active_holds = new Json.Builder().begin_array();
+ foreach (var action in active_profile_holds) {
+ active_holds.add_value(new Json.Builder()
+ .begin_object()
+ .set_member_name("application_id").add_string_value(action.application_id)
+ .set_member_name("profile").add_string_value(action.profile)
+ .set_member_name("reason").add_string_value(action.reason)
+ .end_object()
+ .get_root());
+ }
+
+ var profs = new Json.Builder().begin_array();
+ foreach (var prof in profiles) {
+ profs.add_value(new Json.Builder()
+ .begin_object()
+ .set_member_name("profie").add_string_value(prof.profile)
+ .set_member_name("driver").add_string_value(prof.driver)
+ .set_member_name("cpu_driver").add_string_value(prof.cpu_driver)
+ .set_member_name("platform_driver").add_string_value(prof.platform_driver)
+ .end_object()
+ .get_root());
+ }
+
+ return Json.to_string(new Json.Builder()
+ .begin_object()
+ .set_member_name("active_profile").add_string_value(active_profile)
+ .set_member_name("icon_name").add_string_value(icon_name)
+ .set_member_name("performance_degraded").add_string_value(performance_degraded)
+ .set_member_name("performance_inhibited").add_string_value(performance_inhibited)
+ .set_member_name("actions").add_value(acts.end_array().get_root())
+ .set_member_name("active_profile_holds").add_value(active_holds.end_array().get_root())
+ .set_member_name("profiles").add_value(profs.end_array().get_root())
+ .end_object()
+ .get_root(), false);
+ }
+}
+
+public struct Profile {
+ public string profile;
+ public string cpu_driver;
+ public string platform_driver;
+ public string driver;
+}
+
+public struct Hold {
+ public string application_id;
+ public string profile;
+ public string reason;
+}
+
+private string kebab_case(string pascal_case) {
+ StringBuilder kebab_case = new StringBuilder();
+
+ for (int i = 0; i < pascal_case.length; i++) {
+ char c = pascal_case[i];
+
+ if (c >= 'A' && c <= 'Z') {
+ if (i != 0) {
+ kebab_case.append_c('-');
+ }
+
+ kebab_case.append_c((char)(c + 32));
+ } else {
+ kebab_case.append_c(c);
+ }
+ }
+
+ return kebab_case.str;
+}
+}
diff --git a/lib/powerprofiles/version b/lib/powerprofiles/version
new file mode 100644
index 0000000..6e8bf73
--- /dev/null
+++ b/lib/powerprofiles/version
@@ -0,0 +1 @@
+0.1.0