wmcalc: Use version number from autoconf.
[dockapps.git] / wmbattery / simplehal.c
blobcf8531d0647fa108149aa24a72cb216cf6d17441
1 /* Not particularly good interface to hal, for programs that used to use
2 * apm.
3 */
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #include <unistd.h>
9 #include <libhal.h>
10 #include "apm.h"
12 static DBusConnection *dbus_ctx;
13 static LibHalContext *hal_ctx;
15 int num_ac_adapters = 0;
16 int num_batteries = 0;
17 char **ac_adapters = NULL;
18 char **batteries = NULL;
20 int connect_hal(void)
22 DBusError error;
24 dbus_error_init(&error);
25 dbus_ctx = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error);
26 if (dbus_ctx == NULL) {
27 fprintf(stderr, "error: dbus_bus_get: %s: %s\n",
28 error.name, error.message);
29 LIBHAL_FREE_DBUS_ERROR(&error);
30 return 0;
32 hal_ctx = libhal_ctx_new();
33 if (hal_ctx == NULL) {
34 fprintf(stderr, "error: libhal_ctx_new\n");
35 LIBHAL_FREE_DBUS_ERROR(&error);
36 return 0;
38 if (!libhal_ctx_set_dbus_connection(hal_ctx, dbus_ctx)) {
39 fprintf(stderr, "error: libhal_ctx_set_dbus_connection: %s: %s\n",
40 error.name, error.message);
41 LIBHAL_FREE_DBUS_ERROR(&error);
42 return 0;
44 if (!libhal_ctx_init(hal_ctx, &error)) {
45 if (dbus_error_is_set(&error)) {
46 fprintf(stderr, "error: libhal_ctx_init: %s: %s\n", error.name, error.message);
47 LIBHAL_FREE_DBUS_ERROR(&error);
49 fprintf(stderr, "Could not initialise connection to hald.\n"
50 "Normally this means the HAL daemon (hald) is not running or not ready.\n");
51 return 0;
54 return 1;
57 int hal_ready(void)
59 if (hal_ctx && dbus_connection_get_is_connected(dbus_ctx)) {
60 return 1;
61 } else {
62 /* The messy business of reconnecting.
63 * dbus's design is crap when it comes to reconnecting.
64 * If dbus is down, can't actually close the connection to hal,
65 * since libhal wants to use dbus to do it. */
66 if (dbus_ctx) {
67 dbus_connection_close(dbus_ctx);
68 dbus_connection_unref(dbus_ctx);
70 dbus_ctx = NULL;
71 hal_ctx = NULL;
73 return connect_hal();
77 signed int get_hal_int(const char *udi, const char *key, int optional)
79 int ret;
80 DBusError error;
82 if (!hal_ready())
83 return -1;
85 dbus_error_init(&error);
87 ret = libhal_device_get_property_int (hal_ctx, udi, key, &error);
89 if (!dbus_error_is_set(&error)) {
90 return ret;
91 } else {
92 if (!optional) {
93 fprintf(stderr, "error: libhal_device_get_property_int: %s: %s\n",
94 error.name, error.message);
96 dbus_error_free(&error);
97 return -1;
101 signed int get_hal_bool(const char *udi, const char *key, int optional)
103 int ret;
104 DBusError error;
106 if (!hal_ready())
107 return -1;
109 dbus_error_init(&error);
111 ret = libhal_device_get_property_bool(hal_ctx, udi, key, &error);
113 if (!dbus_error_is_set(&error)) {
114 return ret;
115 } else {
116 if (!optional) {
117 fprintf(stderr, "error: libhal_device_get_property_bool: %s: %s\n",
118 error.name, error.message);
120 dbus_error_free(&error);
121 return -1;
125 void find_devices(void)
127 DBusError error;
129 dbus_error_init(&error);
131 if (ac_adapters)
132 libhal_free_string_array(ac_adapters);
133 ac_adapters = libhal_find_device_by_capability(hal_ctx, "ac_adapter",
134 &num_ac_adapters, &error);
135 if (dbus_error_is_set(&error)) {
136 fprintf(stderr, "error: %s: %s\n", error.name, error.message);
137 LIBHAL_FREE_DBUS_ERROR(&error);
140 if (batteries)
141 libhal_free_string_array(batteries);
142 batteries = libhal_find_device_by_capability(hal_ctx, "battery",
143 &num_batteries, &error);
144 if (dbus_error_is_set(&error)) {
145 fprintf(stderr, "error: %s: %s\n", error.name, error.message);
146 LIBHAL_FREE_DBUS_ERROR(&error);
150 int simplehal_supported(void)
152 if (!connect_hal()) {
153 return 0;
154 } else {
155 find_devices();
156 return 1;
160 /* Fill the passed apm_info struct. */
161 int simplehal_read(int battery, apm_info *info)
163 char *device;
164 int i;
166 /* Allow a battery that was not present before to appear. */
167 if (battery > num_batteries)
168 find_devices();
170 info->battery_flags = 0;
171 info->using_minutes = 0;
173 info->ac_line_status = 0;
174 for (i = 0 ; i < num_ac_adapters && !info->ac_line_status ; i++)
175 info->ac_line_status = (get_hal_bool(ac_adapters[i], "ac_adapter.present", 0) == 1);
177 if (battery > num_batteries) {
178 info->battery_percentage = 0;
179 info->battery_time = 0;
180 info->battery_status = BATTERY_STATUS_ABSENT;
181 return 0;
182 } else {
183 device = batteries[battery-1];
186 if (get_hal_bool(device, "battery.present", 0) != 1) {
187 info->battery_percentage = 0;
188 info->battery_time = 0;
189 info->battery_status = BATTERY_STATUS_ABSENT;
190 return 0;
193 /* remaining_time and charge_level.percentage are not a mandatory
194 * keys, so if not present, -1 will be returned */
195 info->battery_time = get_hal_int(device, "battery.remaining_time", 1);
196 info->battery_percentage = get_hal_int(device, "battery.charge_level.percentage", 1);
197 if (get_hal_bool(device, "battery.rechargeable.is_discharging", 0) == 1) {
198 info->battery_status = BATTERY_STATUS_CHARGING;
199 /* charge_level.warning and charge_level.low are not
200 * required to be available; this is good enough */
201 if (info->battery_percentage < 1)
202 info->battery_status = BATTERY_STATUS_CRITICAL;
203 else if (info->battery_percentage < 10)
204 info->battery_status = BATTERY_STATUS_LOW;
205 } else if (info->ac_line_status &&
206 get_hal_bool(device, "battery.rechargeable.is_charging", 0) == 1) {
207 info->battery_status = BATTERY_STATUS_CHARGING;
208 info->battery_flags = info->battery_flags | BATTERY_FLAGS_CHARGING;
209 } else if (info->ac_line_status) {
210 /* Must be fully charged. */
211 info->battery_status = BATTERY_STATUS_HIGH;
212 } else {
213 fprintf(stderr, "unknown battery state\n");
216 return 0;