summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/cli.vala50
-rw-r--r--src/config.vala.in6
-rw-r--r--src/device.vala148
-rw-r--r--src/ifaces.vala90
-rw-r--r--src/kbd.vala64
-rw-r--r--src/meson.build80
-rw-r--r--src/profiles.vala65
-rw-r--r--src/upower.vala58
-rw-r--r--src/utils.vala36
9 files changed, 597 insertions, 0 deletions
diff --git a/src/cli.vala b/src/cli.vala
new file mode 100644
index 0000000..85e70ae
--- /dev/null
+++ b/src/cli.vala
@@ -0,0 +1,50 @@
+static bool help;
+static bool version;
+static bool monitor;
+
+const OptionEntry[] options = {
+ { "version", 'v', OptionFlags.NONE, OptionArg.NONE, ref version, null, null },
+ { "help", 'h', OptionFlags.NONE, OptionArg.NONE, ref help, null, null },
+ { "monitor", 'm', OptionFlags.NONE, OptionArg.NONE, ref monitor, 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(" -m, --monitor Monitor property changes\n");
+ return 0;
+ }
+
+ if (version) {
+ print(AstalBattery.VERSION);
+ return 0;
+ }
+
+ var battery = AstalBattery.get_default();
+ print("%s\n", AstalBattery.to_json(battery));
+
+ if (monitor) {
+ battery.notify.connect(() => {
+ print("%s\n", AstalBattery.to_json(battery));
+ });
+ new GLib.MainLoop(null, false).run();
+ }
+
+ return 0;
+}
diff --git a/src/config.vala.in b/src/config.vala.in
new file mode 100644
index 0000000..6e7f77e
--- /dev/null
+++ b/src/config.vala.in
@@ -0,0 +1,6 @@
+namespace AstalBattery {
+ 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/src/device.vala b/src/device.vala
new file mode 100644
index 0000000..2dc03eb
--- /dev/null
+++ b/src/device.vala
@@ -0,0 +1,148 @@
+namespace AstalBattery {
+public Device get_default() {
+ return Device.get_default();
+}
+
+public class Device : Object {
+ private static Device display_device;
+ public static Device? get_default() {
+ if (display_device != null)
+ return display_device;
+
+ try {
+ display_device = new Device(
+ "/org/freedesktop/UPower/devices/DisplayDevice");
+
+ return display_device;
+ } catch (Error error) {
+ critical(error.message);
+ }
+ return null;
+ }
+
+ private Properties props;
+ private IUPowerDevice proxy;
+
+ public DeviceType device_type {
+ get {
+ Value value = Value(Type.UINT);
+ proxy.get_property("name", ref value);
+ return value.get_uint();
+ }
+ }
+
+ public string native_path { owned get { return proxy.native_path; } }
+ public string vendor { owned get { return proxy.vendor; } }
+ public string model { owned get { return proxy.model; } }
+ public string serial { owned get { return proxy.serial; } }
+ public uint64 update_time { get { return proxy.update_time; } }
+ public bool power_supply { get { return proxy.power_supply; } }
+ public bool has_history { get { return proxy.has_history; } }
+ public bool has_statistics { get { return proxy.has_statistics; } }
+ public bool online { get { return proxy.online; } }
+ public double energy { get { return proxy.energy; } }
+ public double energy_empty { get { return proxy.energy_empty; } }
+ public double energy_full { get { return proxy.energy_full; } }
+ public double energy_full_design { get { return proxy.energy_full_design; } }
+ public double energy_rate { get { return proxy.energy_rate; } }
+ public double voltage { get { return proxy.voltage; } }
+ public int charge_cycles { get { return proxy.charge_cycles; } }
+ public double luminosity { get { return proxy.luminosity; } }
+ public int64 time_to_empty { get { return proxy.time_to_empty; } }
+ public int64 time_to_full { get { return proxy.time_to_full; }}
+ public double percentage { get { return proxy.percentage / 100; } }
+ public double temperature { get { return proxy.temperature; } }
+ public bool is_present { get { return proxy.is_present; } }
+ public DeviceState state { get { return proxy.state; } }
+ public bool is_rechargable { get { return proxy.is_rechargable; } }
+ public double capacitiy { get { return proxy.capacitiy; } }
+ public DeviceTechnology technology { get { return proxy.technology; } }
+ public WarningLevel warning_level { get { return proxy.warning_level; } }
+ public BatteryLevel battery_level { get { return proxy.battery_level; } }
+ public string icon_name { owned get { return proxy.icon_name; } }
+
+ public Device(string path) throws Error {
+ proxy = Bus.get_proxy_sync(BusType.SYSTEM, "org.freedesktop.UPower", path);
+ props = Bus.get_proxy_sync(BusType.SYSTEM, "org.freedesktop.UPower", path);
+
+ props.properties_changed.connect((iface, vardict) => {
+ foreach (var key in vardict.get_keys()) {
+ var prop = pascal_to_kebab_case(key);
+ if (get_class().find_property(prop) != null)
+ notify_property(prop);
+ }
+ });
+ }
+}
+
+public enum DeviceType {
+ UNKNOWN = 0,
+ LINE_POWER,
+ BATTERY,
+ UPS,
+ MONITOR,
+ MOUSE,
+ KEYBOARD,
+ PDA,
+ PHONE,
+ MEDIA_PLAYER,
+ TABLET,
+ COMPUTER,
+ GAMING_INPUT,
+ PEN,
+ TOUCHPAD,
+ MODEM,
+ NETWORK,
+ HEADSET,
+ SPEAKERS,
+ HEADPHONES,
+ VIDEO,
+ OTHER_AUDIO,
+ REMOVE_CONTROL,
+ PRINTER,
+ SCANNER,
+ CAMERA,
+ WEARABLE,
+ TOY,
+ BLUETOOTH_GENERIC,
+}
+
+public enum DeviceState {
+ UNKNOWN = 0,
+ CHARGING,
+ DISCHARGING,
+ EMPTY,
+ FULLY_CHARGED,
+ PENDING_CHARGE,
+ PENDING_DISCHARGE,
+}
+
+public enum DeviceTechnology {
+ UNKNOWN = 0,
+ LITHIUM_ION,
+ LITHIUM_POLYMER,
+ LITHIUM_IRON_PHOSPHATE,
+ LEAD_ACID,
+ NICKEL_CADMIUM,
+ NICKEL_METAL_HYDRIDE,
+}
+
+public enum WarningLevel {
+ UNKNOWN = 0,
+ NONE,
+ DISCHARGING,
+ LOW,
+ CRITICIAL,
+ ACTION,
+}
+
+public enum BatteryLevel {
+ UNKNOWN = 0,
+ NONE,
+ LOW,
+ CRITICIAL,
+ NORMAL,
+ HIGH,
+ FULL,
+}
+}
diff --git a/src/ifaces.vala b/src/ifaces.vala
new file mode 100644
index 0000000..9c769d1
--- /dev/null
+++ b/src/ifaces.vala
@@ -0,0 +1,90 @@
+namespace AstalBattery {
+[DBus (name = "org.freedesktop.DBus.Properties")]
+public interface Properties : Object {
+ public signal void properties_changed (
+ string iface_name,
+ HashTable<string, Variant> props,
+ string[] invalidated_props
+ );
+}
+
+[DBus (name = "org.freedesktop.UPower")]
+interface IUPower : Object {
+ public abstract string[] enumerate_devices() throws Error;
+ public abstract string get_display_device() throws Error;
+ public abstract string get_critical_action() throws Error;
+
+ public signal void device_added(string object_path);
+ public signal void device_removed(string object_path);
+
+ public abstract string daemon_version { owned get; }
+ public abstract bool on_battery { get; }
+ public abstract bool lid_is_closed { get; }
+ public abstract bool lis_is_present { get; }
+}
+
+[DBus (name = "org.freedesktop.UPower.KbdBacklight")]
+interface IUPowerKdbBacklight : Object {
+ public abstract int get_brightness() throws Error;
+ public abstract int get_max_brightness() throws Error;
+ public abstract void set_brightness(int value) throws Error;
+
+ public signal void brightness_changed(int value);
+ public signal void brightness_changed_with_source(int value, string source);
+}
+
+[DBus (name = "org.freedesktop.UPower.Device")]
+public interface IUPowerDevice : Object {
+ // public abstract void refresh() throws Error;
+ // public abstract void get_history();
+ // public abstract void get_statistics();
+
+ // incompatible with gobject
+ // public abstract uint type { get; }
+ public abstract string native_path { owned get; }
+ public abstract string vendor { owned get; }
+ public abstract string model { owned get; }
+ public abstract string serial { owned get; }
+ public abstract uint64 update_time { get; }
+ public abstract bool power_supply { get; }
+ public abstract bool has_history { get; }
+ public abstract bool has_statistics { get; }
+ public abstract bool online { get; }
+ public abstract double energy { get; }
+ public abstract double energy_empty { get; }
+ public abstract double energy_full { get; }
+ public abstract double energy_full_design { get; }
+ public abstract double energy_rate { get; }
+ public abstract double voltage { get; }
+ public abstract int charge_cycles { get; }
+ public abstract double luminosity { get; }
+ public abstract int64 time_to_empty { get; }
+ public abstract int64 time_to_full { get; }
+ public abstract double percentage { get; }
+ public abstract double temperature { get; }
+ public abstract bool is_present { get; }
+ public abstract uint state { get; }
+ public abstract bool is_rechargable { get; }
+ public abstract double capacitiy { get; }
+ public abstract uint technology { get; }
+ public abstract uint warning_level { get; }
+ public abstract uint battery_level { get; }
+ public abstract string icon_name { owned get; }
+}
+
+[DBus (name = "org.freedesktop.UPower.PowerProfiles")]
+public interface IPowerProfiles : Object {
+ public abstract string[] actions { owned get; }
+ public abstract string active_profile { owned get; }
+ 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 uint 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;
+}
+}
diff --git a/src/kbd.vala b/src/kbd.vala
new file mode 100644
index 0000000..13d722e
--- /dev/null
+++ b/src/kbd.vala
@@ -0,0 +1,64 @@
+namespace AstalBattery {
+public KbdBacklight get_keyboard() {
+ return KbdBacklight.get_default();
+}
+
+public class KbdBacklight : Object {
+ private IUPowerKdbBacklight proxy;
+
+ private static KbdBacklight instance;
+ public static KbdBacklight? get_default() {
+ if (instance != null)
+ return instance;
+
+ try {
+ instance = new KbdBacklight();
+ return instance;
+ } catch (Error error) {
+ critical(error.message);
+ return null;
+ }
+ }
+
+ public int brightness {
+ get {
+ try {
+ return proxy.get_brightness();
+ } catch (Error error) {
+ critical(error.message);
+ return 0;
+ }
+ }
+ set {
+ try {
+ proxy.set_brightness(value);
+ } catch (Error error) {
+ critical(error.message);
+ }
+ }
+ }
+
+ public int max_brightness {
+ get {
+ try {
+ return proxy.get_max_brightness();
+ } catch (Error error) {
+ critical(error.message);
+ return 0;
+ }
+ }
+ }
+
+ public KbdBacklight() throws Error {
+ proxy = Bus.get_proxy_sync(
+ BusType.SYSTEM,
+ "org.freedesktop.UPower",
+ "/org/freedesktop/UPower/KbdBacklight"
+ );
+
+ proxy.brightness_changed.connect(() => {
+ notify_property("brightness");
+ });
+ }
+}
+}
diff --git a/src/meson.build b/src/meson.build
new file mode 100644
index 0000000..9de2aad
--- /dev/null
+++ b/src/meson.build
@@ -0,0 +1,80 @@
+version_split = meson.project_version().split('.')
+api_version = version_split[0] + '.' + version_split[1]
+gir = 'AstalBattery-' + api_version + '.gir'
+typelib = 'AstalBattery-' + api_version + '.typelib'
+so = 'lib' + meson.project_name() + '.so.' + meson.project_version()
+
+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('gio-2.0'),
+ dependency('gobject-2.0'),
+]
+
+sources = [
+ config,
+ 'ifaces.vala',
+ 'device.vala',
+ 'upower.vala',
+ 'kbd.vala',
+ 'profiles.vala',
+ 'utils.vala',
+]
+
+if get_option('lib')
+ lib = library(
+ meson.project_name(),
+ sources,
+ dependencies: deps,
+ vala_header: meson.project_name() + '-' + api_version + '.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/src/profiles.vala b/src/profiles.vala
new file mode 100644
index 0000000..4b43923
--- /dev/null
+++ b/src/profiles.vala
@@ -0,0 +1,65 @@
+namespace AstalBattery {
+public PowerProfiles get_power_profiles() {
+ return PowerProfiles.get_default();
+}
+
+public class PowerProfiles : Object {
+ private static PowerProfiles instance;
+ public static PowerProfiles get_default() {
+ if (instance != null)
+ return instance;
+
+ instance = new PowerProfiles();
+ return instance;
+ }
+
+ private IPowerProfiles proxy;
+ private Properties props;
+
+ public string[] actions { owned get { return proxy.actions; } }
+ public string active_profile { owned get { return proxy.active_profile; } }
+ public HashTable<string, Variant>[] active_profile_holds { owned get { return proxy.active_profile_holds; } }
+ public string performance_degraded { owned get { return proxy.performance_degraded; } }
+ public string performance_inhibited { owned get { return proxy.performance_inhibited; } }
+ public HashTable<string, Variant>[] profiles { owned get { return proxy.profiles; } }
+ public string version { owned get { return proxy.version; } }
+
+ public signal uint profile_released (uint cookie);
+
+ public uint hold_profile(string profile, string reason, string application_id) throws Error {
+ return proxy.hold_profile(profile, reason, application_id);
+ }
+
+ public void release_profile(uint cookie) throws Error {
+ proxy.release_profile(cookie);
+ }
+
+ construct {
+ try {
+ proxy = Bus.get_proxy_sync(
+ BusType.SYSTEM,
+ "org.freedesktop.UPower.PowerProfiles",
+ "/org/freedesktop/UPower/PowerProfiles"
+ );
+
+ props = Bus.get_proxy_sync(
+ BusType.SYSTEM,
+ "org.freedesktop.UPower.PowerProfiles",
+ "/org/freedesktop/UPower/PowerProfiles"
+ );
+
+ props.properties_changed.connect((iface, vardict) => {
+ foreach (var key in vardict.get_keys()) {
+ var prop = pascal_to_kebab_case(key);
+ if (get_class().find_property(prop) != null)
+ notify_property(prop);
+ }
+ });
+
+ proxy.profile_released.connect((cookie) => profile_released(cookie));
+ } catch (Error error) {
+ critical(error.message);
+ }
+ }
+}
+}
diff --git a/src/upower.vala b/src/upower.vala
new file mode 100644
index 0000000..9c18ffd
--- /dev/null
+++ b/src/upower.vala
@@ -0,0 +1,58 @@
+namespace AstalBattery {
+public class UPower : Object {
+ private IUPower proxy;
+ private HashTable<string, Device> _devices =
+ new HashTable<string, Device>(str_hash, str_equal);
+
+ public List<weak Device> devices {
+ owned get { return _devices.get_values(); }
+ }
+
+ public signal void device_added(Device device);
+ public signal void device_removed(Device device);
+
+ public Device display_device { owned get { return Device.get_default(); }}
+
+ public string daemon_version { owned get { return proxy.daemon_version; } }
+ public bool on_battery { get { return proxy.on_battery; } }
+ public bool lid_is_closed { get { return proxy.lid_is_closed; } }
+ public bool lis_is_present { get { return proxy.lid_is_closed; } }
+
+ public string critical_action {
+ owned get {
+ try {
+ return proxy.get_critical_action();
+ } catch (Error error) {
+ critical(error.message);
+ return "";
+ }
+ }
+ }
+
+ construct {
+ try {
+ proxy = Bus.get_proxy_sync(
+ BusType.SYSTEM,
+ "org.freedesktop.UPower",
+ "/org/freedesktop/UPower"
+ );
+
+ foreach (var path in proxy.enumerate_devices())
+ _devices.set(path, new Device(path));
+
+ proxy.device_added.connect((path) => {
+ _devices.set(path, new Device(path));
+ notify_property("devices");
+ });
+
+ proxy.device_removed.connect((path) => {
+ device_removed(_devices.get(path));
+ _devices.remove(path);
+ notify_property("devices");
+ });
+ } catch (Error error) {
+ critical(error.message);
+ }
+ }
+}
+}
diff --git a/src/utils.vala b/src/utils.vala
new file mode 100644
index 0000000..de22f18
--- /dev/null
+++ b/src/utils.vala
@@ -0,0 +1,36 @@
+namespace AstalBattery{
+internal string pascal_to_kebab_case(string pascal) {
+ StringBuilder kebab = new StringBuilder();
+
+ for (int i = 0; i < pascal.length; i++) {
+ char c = pascal[i];
+ if (c.isupper()) {
+ if (i != 0)
+ kebab.append_c('-');
+
+ kebab.append_c(c.tolower());
+ } else {
+ kebab.append_c(c);
+ }
+ }
+
+ return kebab.str;
+}
+
+internal string to_json(AstalBattery.Device device) {
+ string s = "unknown";
+ if (device.state == AstalBattery.DeviceState.CHARGING)
+ s = "charging";
+ if (device.state == AstalBattery.DeviceState.DISCHARGING)
+ s = "discharging";
+ if (device.state == AstalBattery.DeviceState.FULLY_CHARGED)
+ s = "fully_charged";
+
+ var p = device.percentage;
+ var i = device.icon_name;
+ var r = device.state == AstalBattery.DeviceState.CHARGING
+ ? device.time_to_full : device.time_to_empty;
+
+ return "{ \"percentage\": %f, \"state\": \"%s\", \"icon_name\": \"%s\", \"time_remaining\": %f }".printf(p, s, i, r);
+}
+}