/* Not particularly good interface to hal, for programs that used to use * apm. */ #include #include #include #include #include #include "apm.h" static DBusConnection *dbus_ctx; static LibHalContext *hal_ctx; int num_ac_adapters = 0; int num_batteries = 0; char **ac_adapters = NULL; char **batteries = NULL; int connect_hal(void) { DBusError error; dbus_error_init(&error); dbus_ctx = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error); if (dbus_ctx == NULL) { fprintf(stderr, "error: dbus_bus_get: %s: %s\n", error.name, error.message); LIBHAL_FREE_DBUS_ERROR(&error); return 0; } hal_ctx = libhal_ctx_new(); if (hal_ctx == NULL) { fprintf(stderr, "error: libhal_ctx_new\n"); LIBHAL_FREE_DBUS_ERROR(&error); return 0; } if (!libhal_ctx_set_dbus_connection(hal_ctx, dbus_ctx)) { fprintf(stderr, "error: libhal_ctx_set_dbus_connection: %s: %s\n", error.name, error.message); LIBHAL_FREE_DBUS_ERROR(&error); return 0; } if (!libhal_ctx_init(hal_ctx, &error)) { if (dbus_error_is_set(&error)) { fprintf(stderr, "error: libhal_ctx_init: %s: %s\n", error.name, error.message); LIBHAL_FREE_DBUS_ERROR(&error); } fprintf(stderr, "Could not initialise connection to hald.\n" "Normally this means the HAL daemon (hald) is not running or not ready.\n"); return 0; } return 1; } int hal_ready(void) { if (hal_ctx && dbus_connection_get_is_connected(dbus_ctx)) { return 1; } else { /* The messy business of reconnecting. * dbus's design is crap when it comes to reconnecting. * If dbus is down, can't actually close the connection to hal, * since libhal wants to use dbus to do it. */ if (dbus_ctx) { dbus_connection_close(dbus_ctx); dbus_connection_unref(dbus_ctx); } dbus_ctx = NULL; hal_ctx = NULL; return connect_hal(); } } signed int get_hal_int(const char *udi, const char *key, int optional) { int ret; DBusError error; if (!hal_ready()) return -1; dbus_error_init(&error); ret = libhal_device_get_property_int (hal_ctx, udi, key, &error); if (!dbus_error_is_set(&error)) { return ret; } else { if (!optional) { fprintf(stderr, "error: libhal_device_get_property_int: %s: %s\n", error.name, error.message); } dbus_error_free(&error); return -1; } } signed int get_hal_bool(const char *udi, const char *key, int optional) { int ret; DBusError error; if (!hal_ready()) return -1; dbus_error_init(&error); ret = libhal_device_get_property_bool(hal_ctx, udi, key, &error); if (!dbus_error_is_set(&error)) { return ret; } else { if (!optional) { fprintf(stderr, "error: libhal_device_get_property_bool: %s: %s\n", error.name, error.message); } dbus_error_free(&error); return -1; } } void find_devices(void) { DBusError error; dbus_error_init(&error); if (ac_adapters) libhal_free_string_array(ac_adapters); ac_adapters = libhal_find_device_by_capability(hal_ctx, "ac_adapter", &num_ac_adapters, &error); if (dbus_error_is_set(&error)) { fprintf(stderr, "error: %s: %s\n", error.name, error.message); LIBHAL_FREE_DBUS_ERROR(&error); } if (batteries) libhal_free_string_array(batteries); batteries = libhal_find_device_by_capability(hal_ctx, "battery", &num_batteries, &error); if (dbus_error_is_set(&error)) { fprintf(stderr, "error: %s: %s\n", error.name, error.message); LIBHAL_FREE_DBUS_ERROR(&error); } } int simplehal_supported(void) { if (!connect_hal()) { return 0; } else { find_devices(); return 1; } } /* Fill the passed apm_info struct. */ int simplehal_read(int battery, apm_info *info) { char *device; int i; /* Allow a battery that was not present before to appear. */ if (battery > num_batteries) find_devices(); info->battery_flags = 0; info->using_minutes = 0; info->ac_line_status = 0; for (i = 0 ; i < num_ac_adapters && !info->ac_line_status ; i++) info->ac_line_status = (get_hal_bool(ac_adapters[i], "ac_adapter.present", 0) == 1); if (battery > num_batteries) { info->battery_percentage = 0; info->battery_time = 0; info->battery_status = BATTERY_STATUS_ABSENT; return 0; } else { device = batteries[battery-1]; } if (get_hal_bool(device, "battery.present", 0) != 1) { info->battery_percentage = 0; info->battery_time = 0; info->battery_status = BATTERY_STATUS_ABSENT; return 0; } /* remaining_time and charge_level.percentage are not a mandatory * keys, so if not present, -1 will be returned */ info->battery_time = get_hal_int(device, "battery.remaining_time", 1); info->battery_percentage = get_hal_int(device, "battery.charge_level.percentage", 1); if (get_hal_bool(device, "battery.rechargeable.is_discharging", 0) == 1) { info->battery_status = BATTERY_STATUS_CHARGING; /* charge_level.warning and charge_level.low are not * required to be available; this is good enough */ if (info->battery_percentage < 1) info->battery_status = BATTERY_STATUS_CRITICAL; else if (info->battery_percentage < 10) info->battery_status = BATTERY_STATUS_LOW; } else if (info->ac_line_status && get_hal_bool(device, "battery.rechargeable.is_charging", 0) == 1) { info->battery_status = BATTERY_STATUS_CHARGING; info->battery_flags = info->battery_flags | BATTERY_FLAGS_CHARGING; } else if (info->ac_line_status) { /* Must be fully charged. */ info->battery_status = BATTERY_STATUS_HIGH; } else { fprintf(stderr, "unknown battery state\n"); } return 0; }