#include "batman.h" #define BUS "org.freedesktop.UPower" #define PATH "/org/freedesktop/UPower" #define IFACE "org.freedesktop.UPower" EINTERN extern Eina_List *batman_device_batteries; EINTERN extern Eina_List *batman_device_ac_adapters; EINTERN extern double batman_init_time; static Eldbus_Connection *conn; static Eldbus_Proxy *upower_proxy; typedef struct _Upower_Data Upower_Data; struct _Upower_Data { Eldbus_Proxy *proxy; Instance *inst; }; static void _battery_free(Battery *bat) { Eldbus_Object *obj = eldbus_proxy_object_get(bat->proxy); eldbus_proxy_unref(bat->proxy); eldbus_object_unref(obj); batman_device_batteries = eina_list_remove(batman_device_batteries, bat); eina_stringshare_del(bat->udi); if (bat->model) eina_stringshare_del(bat->model); if (bat->vendor) eina_stringshare_del(bat->vendor); E_FREE(bat); } static void _ac_free(Ac_Adapter *ac) { Eldbus_Object *obj = eldbus_proxy_object_get(ac->proxy); eldbus_proxy_unref(ac->proxy); eldbus_object_unref(obj); batman_device_ac_adapters = eina_list_remove(batman_device_ac_adapters, ac); eina_stringshare_del(ac->udi); E_FREE(ac); } static void _ac_get_all_cb(void *data, const Eldbus_Message *msg, Eldbus_Pending *pending EINA_UNUSED) { Ac_Adapter *ac = data; Eldbus_Message_Iter *array, *dict, *variant; if (!eldbus_message_arguments_get(msg, "a{sv}", &array)) return; while (eldbus_message_iter_get_and_next(array, 'e', &dict)) { const char *key; if (!eldbus_message_iter_arguments_get(dict, "sv", &key, &variant)) continue; if (!strcmp(key, "Online")) { Eina_Bool b; eldbus_message_iter_arguments_get(variant, "b", &b); ac->present = b; break; } } _batman_device_update(ac->inst); } static void _ac_changed_cb(void *data, const Eldbus_Message *msg EINA_UNUSED) { Ac_Adapter *ac = data; eldbus_proxy_property_get_all(ac->proxy, _ac_get_all_cb, ac); } static void _process_ac(Eldbus_Proxy *proxy, Instance *inst) { Ac_Adapter *ac; ac = E_NEW(Ac_Adapter, 1); if (!ac) goto error; ac->inst = inst; ac->proxy = proxy; ac->udi = eina_stringshare_add(eldbus_object_path_get(eldbus_proxy_object_get(proxy))); eldbus_proxy_property_get_all(proxy, _ac_get_all_cb, ac); eldbus_proxy_signal_handler_add(proxy, "Changed", _ac_changed_cb, ac); batman_device_ac_adapters = eina_list_append(batman_device_ac_adapters, ac); return; error: eldbus_object_unref(eldbus_proxy_object_get(proxy)); eldbus_proxy_unref(proxy); return; } static const char *bat_techologies[] = { "Unknown", "Lithium ion", "Lithium polymer", "Lithium iron phosphate", "Lead acid", "Nickel cadmium", "Nickel metal hydride" }; static void _bat_get_all_cb(void *data, const Eldbus_Message *msg, Eldbus_Pending *pending EINA_UNUSED) { Battery *bat = data; Eldbus_Message_Iter *array, *dict, *variant; bat->got_prop = EINA_TRUE; if (!eldbus_message_arguments_get(msg, "a{sv}", &array)) return; while (eldbus_message_iter_get_and_next(array, 'e', &dict)) { const char *key; union { Eina_Bool b; int64_t i64; unsigned u; double d; const char *s; } val; if (!eldbus_message_iter_arguments_get(dict, "sv", &key, &variant)) continue; if (!strcmp(key, "IsPresent")) { eldbus_message_iter_arguments_get(variant, "b", &val.b); bat->present = val.b; } else if (!strcmp(key, "TimeToEmpty")) { eldbus_message_iter_arguments_get(variant, "x", &val.i64); bat->time_left = (int) val.i64; if (bat->time_left > 0) bat->charging = EINA_FALSE; else bat->charging = EINA_TRUE; } else if (!strcmp(key, "Percentage")) { eldbus_message_iter_arguments_get(variant, "d", &val.d); bat->percent = (int) val.d; } else if (!strcmp(key, "Energy")) { eldbus_message_iter_arguments_get(variant, "d", &val.d); bat->current_charge = (int) val.d; } else if (!strcmp(key, "EnergyFullDesign")) { eldbus_message_iter_arguments_get(variant, "d", &val.d); bat->design_charge = (int) val.d; } else if (!strcmp(key, "EnergyFull")) { eldbus_message_iter_arguments_get(variant, "d", &val.d); bat->last_full_charge = (int) val.d; } else if (!strcmp(key, "TimeToFull")) { eldbus_message_iter_arguments_get(variant, "x", &val.i64); bat->time_full = (int) val.i64; } else if (!strcmp(key, "Technology")) { eldbus_message_iter_arguments_get(variant, "u", &val.u); if (val.u > EINA_C_ARRAY_LENGTH(bat_techologies)) val.u = 0; bat->technology = bat_techologies[val.u]; } else if (!strcmp(key, "Model")) { if (!eldbus_message_iter_arguments_get(variant, "s", &val.s)) continue; eina_stringshare_replace(&bat->model, val.s); } else if (!strcmp(key, "Vendor")) { if (!eldbus_message_iter_arguments_get(variant, "s", &val.s)) continue; if (bat->vendor) eina_stringshare_del(bat->vendor); bat->vendor = eina_stringshare_add(val.s); } } _batman_device_update(bat->inst); } static void _bat_changed_cb(void *data, const Eldbus_Message *msg EINA_UNUSED) { Battery *bat = data; eldbus_proxy_property_get_all(bat->proxy, _bat_get_all_cb, bat); } static void _process_battery(Eldbus_Proxy *proxy, Instance *inst) { Battery *bat; bat = E_NEW(Battery, 1); if (!bat) { eldbus_object_unref(eldbus_proxy_object_get(proxy)); eldbus_proxy_unref(proxy); return; } bat->inst = inst; bat->proxy = proxy; bat->udi = eina_stringshare_add(eldbus_object_path_get(eldbus_proxy_object_get(proxy))); eldbus_proxy_property_get_all(proxy, _bat_get_all_cb, bat); eldbus_proxy_signal_handler_add(proxy, "Changed", _bat_changed_cb, bat); batman_device_batteries = eina_list_append(batman_device_batteries, bat); _batman_device_update(bat->inst); } static void _device_type_cb(void *data, const Eldbus_Message *msg, Eldbus_Pending *pending EINA_UNUSED) { Upower_Data *ud = data; Eldbus_Message_Iter *variant; Eldbus_Object *obj; unsigned int type; if (!eldbus_message_arguments_get(msg, "v", &variant)) goto error; eldbus_message_iter_arguments_get(variant, "u", &type); if (type == 1) _process_ac(ud->proxy, ud->inst); else if (type == 2) _process_battery(ud->proxy, ud->inst); else goto error; E_FREE(ud); return; error: obj = eldbus_proxy_object_get(ud->proxy); eldbus_proxy_unref(ud->proxy); eldbus_object_unref(obj); E_FREE(ud); return; } static void _process_enumerate_path(const char *path, Instance *inst) { Eldbus_Object *obj; Eldbus_Proxy *proxy; Upower_Data *ud; obj = eldbus_object_get(conn, BUS, path); EINA_SAFETY_ON_FALSE_RETURN(obj); proxy = eldbus_proxy_get(obj, "org.freedesktop.UPower.Device"); ud = E_NEW(Upower_Data, 1); if (!ud) { eldbus_object_unref(eldbus_proxy_object_get(proxy)); eldbus_proxy_unref(proxy); return; } ud->proxy = proxy; ud->inst = inst; eldbus_proxy_property_get(proxy, "Type", _device_type_cb, ud); } static void _enumerate_cb(void *data, const Eldbus_Message *msg, Eldbus_Pending *pending EINA_UNUSED) { Instance *inst = data; const char *path; Eldbus_Message_Iter *array; if (!eldbus_message_arguments_get(msg, "ao", &array)) return; while (eldbus_message_iter_get_and_next(array, 'o', &path)) _process_enumerate_path(path, inst); } static void _device_added_cb(void *data, const Eldbus_Message *msg) { const char *path; Instance *inst = data; if (!eldbus_message_arguments_get(msg, "o", &path)) return; _process_enumerate_path(path, inst); } static void _device_removed_cb(void *data, const Eldbus_Message *msg) { Battery *bat; Ac_Adapter *ac; const char *path; Instance *inst = data; Eina_List *batteries, *adapters, *l; Eina_Bool exists = EINA_FALSE; if (!eldbus_message_arguments_get(msg, "o", &path)) return; batteries = _batman_battery_find(path); if (eina_list_count(batteries)) { EINA_LIST_FOREACH(batteries, l, bat) { if (inst == bat->inst) { inst = bat->inst; _battery_free(bat); _batman_device_update(inst); exists = EINA_TRUE; } } if (exists) { eina_list_free(batteries); return; } } exists = EINA_FALSE; adapters = _batman_ac_adapter_get(path); if (eina_list_count(adapters)) { EINA_LIST_FOREACH(adapters, l, ac) { if (ac->inst == inst) { inst = ac->inst; _ac_free(ac); _batman_device_update(inst); exists = EINA_TRUE; } } eina_list_free(adapters); } } int _batman_upower_start(Instance *inst) { Eldbus_Object *obj; conn = eldbus_connection_get(ELDBUS_CONNECTION_TYPE_SYSTEM); EINA_SAFETY_ON_NULL_RETURN_VAL(conn, 0); obj = eldbus_object_get(conn, BUS, PATH); EINA_SAFETY_ON_NULL_GOTO(obj, obj_error); upower_proxy = eldbus_proxy_get(obj, IFACE); EINA_SAFETY_ON_NULL_GOTO(upower_proxy, proxy_error); eldbus_proxy_call(upower_proxy, "EnumerateDevices", _enumerate_cb, inst, -1, ""); eldbus_proxy_signal_handler_add(upower_proxy, "DeviceAdded", _device_added_cb, inst); eldbus_proxy_signal_handler_add(upower_proxy, "DeviceRemoved", _device_removed_cb, inst); return 1; proxy_error: eldbus_object_unref(obj); obj_error: eldbus_connection_unref(conn); return 0; } void _batman_upower_stop(void) { Eina_List *list, *list2; Battery *bat; Ac_Adapter *ac; Eldbus_Object *obj; EINA_LIST_FOREACH_SAFE(batman_device_batteries, list, list2, bat) E_FREE_FUNC(bat, _battery_free); EINA_LIST_FOREACH_SAFE(batman_device_ac_adapters, list, list2, ac) E_FREE_FUNC(ac, _ac_free); obj = eldbus_proxy_object_get(upower_proxy); E_FREE_FUNC(upower_proxy, eldbus_proxy_unref); E_FREE_FUNC(obj, eldbus_object_unref); E_FREE_FUNC(conn, eldbus_connection_unref); }