summaryrefslogtreecommitdiff
path: root/src/up-device.c
diff options
context:
space:
mode:
authorRichard Hughes <richard@hughsie.com>2010-01-18 12:26:55 +0000
committerRichard Hughes <richard@hughsie.com>2010-01-18 12:26:55 +0000
commit15ac5102c8abcbeac6e8da007056e493d4fef1e6 (patch)
tree644ce3fecec5540cb608ad2e22175adbd3404a0a /src/up-device.c
parent7be60e43e298a922576cafc47c89c11929c06da9 (diff)
downloadupower-15ac5102c8abcbeac6e8da007056e493d4fef1e6.tar.gz
trivial: Rename a lot of the source files from dkp-foo to up-foo, no API or ABI changes
Diffstat (limited to 'src/up-device.c')
-rw-r--r--src/up-device.c1224
1 files changed, 1224 insertions, 0 deletions
diff --git a/src/up-device.c b/src/up-device.c
new file mode 100644
index 0000000..2a5d0d6
--- /dev/null
+++ b/src/up-device.c
@@ -0,0 +1,1224 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2008 David Zeuthen <davidz@redhat.com>
+ * Copyright (C) 2008-2009 Richard Hughes <richard@hughsie.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <string.h>
+
+#include <glib.h>
+#include <glib/gstdio.h>
+#include <glib/gi18n-lib.h>
+#include <glib-object.h>
+#include <dbus/dbus-glib.h>
+#include <dbus/dbus-glib-lowlevel.h>
+
+#include "egg-debug.h"
+
+#include "up-native.h"
+#include "up-device.h"
+#include "up-history.h"
+#include "up-history-obj.h"
+#include "up-stats-obj.h"
+#include "up-marshal.h"
+#include "up-device-glue.h"
+
+struct DkpDevicePrivate
+{
+ gchar *object_path;
+ DBusGConnection *system_bus_connection;
+ DBusGProxy *system_bus_proxy;
+ DkpDaemon *daemon;
+ DkpHistory *history;
+ GObject *native;
+ gboolean has_ever_refresh;
+ gboolean during_coldplug;
+
+ /* properties */
+ guint64 update_time;
+ gchar *vendor;
+ gchar *model;
+ gchar *serial;
+ gchar *native_path;
+ gboolean power_supply;
+ gboolean online;
+ gboolean is_present;
+ gboolean is_rechargeable;
+ gboolean has_history;
+ gboolean has_statistics;
+ DkpDeviceType type;
+ DkpDeviceState state;
+ DkpDeviceTechnology technology;
+ gdouble capacity; /* percent */
+ gdouble energy; /* Watt Hours */
+ gdouble energy_empty; /* Watt Hours */
+ gdouble energy_full; /* Watt Hours */
+ gdouble energy_full_design; /* Watt Hours */
+ gdouble energy_rate; /* Watts */
+ gdouble voltage; /* Volts */
+ gint64 time_to_empty; /* seconds */
+ gint64 time_to_full; /* seconds */
+ gdouble percentage; /* percent */
+ gboolean recall_notice;
+ gchar *recall_vendor;
+ gchar *recall_url;
+};
+
+static gboolean dkp_device_register_device (DkpDevice *device);
+
+enum {
+ PROP_0,
+ PROP_NATIVE_PATH,
+ PROP_VENDOR,
+ PROP_MODEL,
+ PROP_SERIAL,
+ PROP_UPDATE_TIME,
+ PROP_TYPE,
+ PROP_ONLINE,
+ PROP_POWER_SUPPLY,
+ PROP_CAPACITY,
+ PROP_IS_PRESENT,
+ PROP_IS_RECHARGEABLE,
+ PROP_HAS_HISTORY,
+ PROP_HAS_STATISTICS,
+ PROP_STATE,
+ PROP_ENERGY,
+ PROP_ENERGY_EMPTY,
+ PROP_ENERGY_FULL,
+ PROP_ENERGY_FULL_DESIGN,
+ PROP_ENERGY_RATE,
+ PROP_VOLTAGE,
+ PROP_TIME_TO_EMPTY,
+ PROP_TIME_TO_FULL,
+ PROP_PERCENTAGE,
+ PROP_TECHNOLOGY,
+ PROP_RECALL_NOTICE,
+ PROP_RECALL_VENDOR,
+ PROP_RECALL_URL,
+ PROP_LAST
+};
+
+enum {
+ SIGNAL_CHANGED,
+ SIGNAL_LAST,
+};
+
+static guint signals[SIGNAL_LAST] = { 0 };
+
+G_DEFINE_TYPE (DkpDevice, dkp_device, G_TYPE_OBJECT)
+#define DKP_DEVICE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), DKP_TYPE_DEVICE, DkpDevicePrivate))
+#define DKP_DBUS_STRUCT_UINT_DOUBLE_UINT (dbus_g_type_get_struct ("GValueArray", \
+ G_TYPE_UINT, G_TYPE_DOUBLE, G_TYPE_UINT, G_TYPE_INVALID))
+#define DKP_DBUS_STRUCT_DOUBLE_DOUBLE (dbus_g_type_get_struct ("GValueArray", \
+ G_TYPE_DOUBLE, G_TYPE_DOUBLE, G_TYPE_INVALID))
+
+/**
+ * dkp_device_error_quark:
+ **/
+GQuark
+dkp_device_error_quark (void)
+{
+ static GQuark ret = 0;
+
+ if (ret == 0) {
+ ret = g_quark_from_static_string ("dkp_device_error");
+ }
+
+ return ret;
+}
+
+#define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC }
+
+/**
+ * dkp_device_error_get_type:
+ **/
+GType
+dkp_device_error_get_type (void)
+{
+ static GType etype = 0;
+
+ if (etype == 0)
+ {
+ static const GEnumValue values[] =
+ {
+ ENUM_ENTRY (DKP_DEVICE_ERROR_GENERAL, "GeneralError"),
+ { 0, 0, 0 }
+ };
+ g_assert (DKP_DEVICE_NUM_ERRORS == G_N_ELEMENTS (values) - 1);
+ etype = g_enum_register_static ("DkpDeviceError", values);
+ }
+ return etype;
+}
+
+/**
+ * dkp_device_get_property:
+ **/
+static void
+dkp_device_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
+{
+ DkpDevice *device = DKP_DEVICE (object);
+ switch (prop_id) {
+ case PROP_NATIVE_PATH:
+ g_value_set_string (value, device->priv->native_path);
+ break;
+ case PROP_VENDOR:
+ g_value_set_string (value, device->priv->vendor);
+ break;
+ case PROP_MODEL:
+ g_value_set_string (value, device->priv->model);
+ break;
+ case PROP_SERIAL:
+ g_value_set_string (value, device->priv->serial);
+ break;
+ case PROP_UPDATE_TIME:
+ g_value_set_uint64 (value, device->priv->update_time);
+ break;
+ case PROP_TYPE:
+ g_value_set_uint (value, device->priv->type);
+ break;
+ case PROP_POWER_SUPPLY:
+ g_value_set_boolean (value, device->priv->power_supply);
+ break;
+ case PROP_ONLINE:
+ g_value_set_boolean (value, device->priv->online);
+ break;
+ case PROP_IS_PRESENT:
+ g_value_set_boolean (value, device->priv->is_present);
+ break;
+ case PROP_IS_RECHARGEABLE:
+ g_value_set_boolean (value, device->priv->is_rechargeable);
+ break;
+ case PROP_HAS_HISTORY:
+ g_value_set_boolean (value, device->priv->has_history);
+ break;
+ case PROP_HAS_STATISTICS:
+ g_value_set_boolean (value, device->priv->has_statistics);
+ break;
+ case PROP_STATE:
+ g_value_set_uint (value, device->priv->state);
+ break;
+ case PROP_CAPACITY:
+ g_value_set_double (value, device->priv->capacity);
+ break;
+ case PROP_ENERGY:
+ g_value_set_double (value, device->priv->energy);
+ break;
+ case PROP_ENERGY_EMPTY:
+ g_value_set_double (value, device->priv->energy_empty);
+ break;
+ case PROP_ENERGY_FULL:
+ g_value_set_double (value, device->priv->energy_full);
+ break;
+ case PROP_ENERGY_FULL_DESIGN:
+ g_value_set_double (value, device->priv->energy_full_design);
+ break;
+ case PROP_ENERGY_RATE:
+ g_value_set_double (value, device->priv->energy_rate);
+ break;
+ case PROP_VOLTAGE:
+ g_value_set_double (value, device->priv->voltage);
+ break;
+ case PROP_TIME_TO_EMPTY:
+ g_value_set_int64 (value, device->priv->time_to_empty);
+ break;
+ case PROP_TIME_TO_FULL:
+ g_value_set_int64 (value, device->priv->time_to_full);
+ break;
+ case PROP_PERCENTAGE:
+ g_value_set_double (value, device->priv->percentage);
+ break;
+ case PROP_TECHNOLOGY:
+ g_value_set_uint (value, device->priv->technology);
+ break;
+ case PROP_RECALL_NOTICE:
+ g_value_set_boolean (value, device->priv->recall_notice);
+ break;
+ case PROP_RECALL_VENDOR:
+ g_value_set_string (value, device->priv->recall_vendor);
+ break;
+ case PROP_RECALL_URL:
+ g_value_set_string (value, device->priv->recall_url);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+/**
+ * dkp_device_set_property:
+ **/
+static void
+dkp_device_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
+{
+ DkpDevice *device = DKP_DEVICE (object);
+
+ switch (prop_id) {
+ case PROP_NATIVE_PATH:
+ g_free (device->priv->native_path);
+ device->priv->native_path = g_strdup (g_value_get_string (value));
+ break;
+ case PROP_VENDOR:
+ g_free (device->priv->vendor);
+ device->priv->vendor = g_strdup (g_value_get_string (value));
+ break;
+ case PROP_MODEL:
+ g_free (device->priv->model);
+ device->priv->model = g_strdup (g_value_get_string (value));
+ break;
+ case PROP_SERIAL:
+ g_free (device->priv->serial);
+ device->priv->serial = g_strdup (g_value_get_string (value));
+ break;
+ case PROP_UPDATE_TIME:
+ device->priv->update_time = g_value_get_uint64 (value);
+ break;
+ case PROP_TYPE:
+ device->priv->type = g_value_get_uint (value);
+ break;
+ case PROP_POWER_SUPPLY:
+ device->priv->power_supply = g_value_get_boolean (value);
+ break;
+ case PROP_ONLINE:
+ device->priv->online = g_value_get_boolean (value);
+ break;
+ case PROP_IS_PRESENT:
+ device->priv->is_present = g_value_get_boolean (value);
+ break;
+ case PROP_IS_RECHARGEABLE:
+ device->priv->is_rechargeable = g_value_get_boolean (value);
+ break;
+ case PROP_HAS_HISTORY:
+ device->priv->has_history = g_value_get_boolean (value);
+ break;
+ case PROP_HAS_STATISTICS:
+ device->priv->has_statistics = g_value_get_boolean (value);
+ break;
+ case PROP_STATE:
+ device->priv->state = g_value_get_uint (value);
+ break;
+ case PROP_CAPACITY:
+ device->priv->capacity = g_value_get_double (value);
+ break;
+ case PROP_ENERGY:
+ device->priv->energy = g_value_get_double (value);
+ break;
+ case PROP_ENERGY_EMPTY:
+ device->priv->energy_empty = g_value_get_double (value);
+ break;
+ case PROP_ENERGY_FULL:
+ device->priv->energy_full = g_value_get_double (value);
+ break;
+ case PROP_ENERGY_FULL_DESIGN:
+ device->priv->energy_full_design = g_value_get_double (value);
+ break;
+ case PROP_ENERGY_RATE:
+ device->priv->energy_rate = g_value_get_double (value);
+ break;
+ case PROP_VOLTAGE:
+ device->priv->voltage = g_value_get_double (value);
+ break;
+ case PROP_TIME_TO_EMPTY:
+ device->priv->time_to_empty = g_value_get_int64 (value);
+ break;
+ case PROP_TIME_TO_FULL:
+ device->priv->time_to_full = g_value_get_int64 (value);
+ break;
+ case PROP_PERCENTAGE:
+ device->priv->percentage = g_value_get_double (value);
+ break;
+ case PROP_TECHNOLOGY:
+ device->priv->technology = g_value_get_uint (value);
+ break;
+ case PROP_RECALL_NOTICE:
+ device->priv->recall_notice = g_value_get_boolean (value);
+ break;
+ case PROP_RECALL_VENDOR:
+ g_free (device->priv->recall_vendor);
+ device->priv->recall_vendor = g_strdup (g_value_get_string (value));
+ break;
+ case PROP_RECALL_URL:
+ g_free (device->priv->recall_url);
+ device->priv->recall_url = g_strdup (g_value_get_string (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+/**
+ * dkp_device_get_on_battery:
+ *
+ * Note: Only implement for system devices, i.e. ones supplying the system
+ **/
+gboolean
+dkp_device_get_on_battery (DkpDevice *device, gboolean *on_battery)
+{
+ DkpDeviceClass *klass = DKP_DEVICE_GET_CLASS (device);
+
+ g_return_val_if_fail (DKP_IS_DEVICE (device), FALSE);
+
+ /* no support */
+ if (klass->get_on_battery == NULL)
+ return FALSE;
+
+ return klass->get_on_battery (device, on_battery);
+}
+
+/**
+ * dkp_device_get_low_battery:
+ *
+ * Note: Only implement for system devices, i.e. ones supplying the system
+ **/
+gboolean
+dkp_device_get_low_battery (DkpDevice *device, gboolean *low_battery)
+{
+ DkpDeviceClass *klass = DKP_DEVICE_GET_CLASS (device);
+
+ g_return_val_if_fail (DKP_IS_DEVICE (device), FALSE);
+
+ /* no support */
+ if (klass->get_low_battery == NULL)
+ return FALSE;
+
+ return klass->get_low_battery (device, low_battery);
+}
+
+/**
+ * dkp_device_get_online:
+ *
+ * Note: Only implement for system devices, i.e. devices supplying the system
+ **/
+gboolean
+dkp_device_get_online (DkpDevice *device, gboolean *online)
+{
+ DkpDeviceClass *klass = DKP_DEVICE_GET_CLASS (device);
+
+ g_return_val_if_fail (DKP_IS_DEVICE (device), FALSE);
+
+ /* no support */
+ if (klass->get_online == NULL)
+ return FALSE;
+
+ return klass->get_online (device, online);
+}
+
+/**
+ * dkp_device_get_id:
+ **/
+static gchar *
+dkp_device_get_id (DkpDevice *device)
+{
+ GString *string;
+ gchar *id = NULL;
+
+ /* line power */
+ if (device->priv->type == DKP_DEVICE_TYPE_LINE_POWER) {
+ goto out;
+
+ /* batteries */
+ } else if (device->priv->type == DKP_DEVICE_TYPE_BATTERY) {
+ /* we don't have an ID if we are not present */
+ if (!device->priv->is_present)
+ goto out;
+
+ string = g_string_new ("");
+
+ /* in an ideal world, model-capacity-serial */
+ if (device->priv->model != NULL && strlen (device->priv->model) > 2) {
+ g_string_append (string, device->priv->model);
+ g_string_append_c (string, '-');
+ }
+ if (device->priv->energy_full_design > 0) {
+ /* FIXME: this may not be stable if we are using voltage_now */
+ g_string_append_printf (string, "%i", (guint) device->priv->energy_full_design);
+ g_string_append_c (string, '-');
+ }
+ if (device->priv->serial != NULL && strlen (device->priv->serial) > 2) {
+ g_string_append (string, device->priv->serial);
+ g_string_append_c (string, '-');
+ }
+
+ /* make sure we are sane */
+ if (string->len == 0) {
+ /* just use something generic */
+ g_string_append (string, "generic_id");
+ } else {
+ /* remove trailing '-' */
+ g_string_set_size (string, string->len - 1);
+ }
+
+ /* the id may have invalid chars that need to be replaced */
+ id = g_string_free (string, FALSE);
+
+ } else {
+ /* generic fallback, get what data we can */
+ string = g_string_new ("");
+ if (device->priv->vendor != NULL) {
+ g_string_append (string, device->priv->vendor);
+ g_string_append_c (string, '-');
+ }
+ if (device->priv->model != NULL) {
+ g_string_append (string, device->priv->model);
+ g_string_append_c (string, '-');
+ }
+ if (device->priv->serial != NULL) {
+ g_string_append (string, device->priv->serial);
+ g_string_append_c (string, '-');
+ }
+
+ /* make sure we are sane */
+ if (string->len == 0) {
+ /* just use something generic */
+ g_string_append (string, "generic_id");
+ } else {
+ /* remove trailing '-' */
+ g_string_set_size (string, string->len - 1);
+ }
+
+ /* the id may have invalid chars that need to be replaced */
+ id = g_string_free (string, FALSE);
+ }
+
+ g_strdelimit (id, "\\\t\"?' /,.", '_');
+
+out:
+ return id;
+}
+
+/**
+ * dkp_device_get_daemon:
+ *
+ * Returns a refcounted #DkpDaemon instance, or %NULL
+ **/
+DkpDaemon *
+dkp_device_get_daemon (DkpDevice *device)
+{
+ if (device->priv->daemon == NULL)
+ return NULL;
+ return g_object_ref (device->priv->daemon);
+}
+
+/**
+ * dkp_device_coldplug:
+ *
+ * Return %TRUE on success, %FALSE if we failed to get data and should be removed
+ **/
+gboolean
+dkp_device_coldplug (DkpDevice *device, DkpDaemon *daemon, GObject *native)
+{
+ gboolean ret;
+ const gchar *native_path;
+ DkpDeviceClass *klass = DKP_DEVICE_GET_CLASS (device);
+ gchar *id = NULL;
+
+ g_return_val_if_fail (DKP_IS_DEVICE (device), FALSE);
+
+ /* save */
+ device->priv->native = g_object_ref (native);
+ device->priv->daemon = g_object_ref (daemon);
+
+ native_path = dkp_native_get_native_path (native);
+ device->priv->native_path = g_strdup (native_path);
+
+ /* stop signals and callbacks */
+ egg_debug ("device now coldplug");
+ g_object_freeze_notify (G_OBJECT(device));
+ device->priv->during_coldplug = TRUE;
+
+ /* coldplug source */
+ if (klass->coldplug != NULL) {
+ ret = klass->coldplug (device);
+ if (!ret) {
+ egg_debug ("failed to coldplug %s", device->priv->native_path);
+ goto out;
+ }
+ }
+
+ /* only put on the bus if we succeeded */
+ ret = dkp_device_register_device (device);
+ if (!ret) {
+ egg_warning ("failed to register device %s", device->priv->native_path);
+ goto out;
+ }
+
+ /* force a refresh, although failure isn't fatal */
+ ret = dkp_device_refresh_internal (device);
+ if (!ret) {
+ egg_debug ("failed to refresh %s", device->priv->native_path);
+
+ /* TODO: refresh should really have seporate
+ * success _and_ changed parameters */
+ ret = TRUE;
+ goto out;
+ }
+
+ /* get the id so we can load the old history */
+ id = dkp_device_get_id (device);
+ if (id != NULL)
+ dkp_history_set_id (device->priv->history, id);
+
+out:
+ /* start signals and callbacks */
+ g_object_thaw_notify (G_OBJECT(device));
+ device->priv->during_coldplug = FALSE;
+ egg_debug ("device now not coldplug");
+ g_free (id);
+ return ret;
+}
+
+/**
+ * dkp_device_get_statistics:
+ **/
+gboolean
+dkp_device_get_statistics (DkpDevice *device, const gchar *type, DBusGMethodInvocation *context)
+{
+ GError *error;
+ GPtrArray *array = NULL;
+ GPtrArray *complex;
+ const DkpStatsObj *obj;
+ GValue *value;
+ guint i;
+
+ g_return_val_if_fail (DKP_IS_DEVICE (device), FALSE);
+ g_return_val_if_fail (type != NULL, FALSE);
+
+ /* doesn't even try to support this */
+ if (!device->priv->has_statistics) {
+ error = g_error_new (DKP_DAEMON_ERROR, DKP_DAEMON_ERROR_GENERAL, "device does not support getting stats");
+ dbus_g_method_return_error (context, error);
+ goto out;
+ }
+
+ /* get the correct data */
+ if (g_strcmp0 (type, "charging") == 0)
+ array = dkp_history_get_profile_data (device->priv->history, TRUE);
+ else if (g_strcmp0 (type, "discharging") == 0)
+ array = dkp_history_get_profile_data (device->priv->history, FALSE);
+
+ /* maybe the device doesn't support histories */
+ if (array == NULL) {
+ error = g_error_new (DKP_DAEMON_ERROR, DKP_DAEMON_ERROR_GENERAL, "device has no statistics");
+ dbus_g_method_return_error (context, error);
+ goto out;
+ }
+
+ /* always 101 items of data */
+ if (array->len != 101) {
+ error = g_error_new (DKP_DAEMON_ERROR, DKP_DAEMON_ERROR_GENERAL, "statistics invalid as have %i items", array->len);
+ dbus_g_method_return_error (context, error);
+ goto out;
+ }
+
+ /* copy data to dbus struct */
+ complex = g_ptr_array_sized_new (array->len);
+ for (i=0; i<array->len; i++) {
+ obj = (const DkpStatsObj *) g_ptr_array_index (array, i);
+ value = g_new0 (GValue, 1);
+ g_value_init (value, DKP_DBUS_STRUCT_DOUBLE_DOUBLE);
+ g_value_take_boxed (value, dbus_g_type_specialized_construct (DKP_DBUS_STRUCT_DOUBLE_DOUBLE));
+ dbus_g_type_struct_set (value, 0, obj->value, 1, obj->accuracy, -1);
+ g_ptr_array_add (complex, g_value_get_boxed (value));
+ g_free (value);
+ }
+
+ dbus_g_method_return (context, complex);
+out:
+ if (array != NULL)
+ g_ptr_array_unref (array);
+ return TRUE;
+}
+
+/**
+ * dkp_device_get_history:
+ **/
+gboolean
+dkp_device_get_history (DkpDevice *device, const gchar *type_string, guint timespan, guint resolution, DBusGMethodInvocation *context)
+{
+ GError *error;
+ GPtrArray *array = NULL;
+ GPtrArray *complex;
+ const DkpHistoryObj *obj;
+ GValue *value;
+ guint i;
+ DkpHistoryType type = DKP_HISTORY_TYPE_UNKNOWN;
+
+ g_return_val_if_fail (DKP_IS_DEVICE (device), FALSE);
+ g_return_val_if_fail (type_string != NULL, FALSE);
+
+ /* doesn't even try to support this */
+ if (!device->priv->has_history) {
+ error = g_error_new (DKP_DAEMON_ERROR, DKP_DAEMON_ERROR_GENERAL, "device does not support getting history");
+ dbus_g_method_return_error (context, error);
+ goto out;
+ }
+
+ /* get the correct data */
+ if (g_strcmp0 (type_string, "rate") == 0)
+ type = DKP_HISTORY_TYPE_RATE;
+ else if (g_strcmp0 (type_string, "charge") == 0)
+ type = DKP_HISTORY_TYPE_CHARGE;
+ else if (g_strcmp0 (type_string, "time-full") == 0)
+ type = DKP_HISTORY_TYPE_TIME_FULL;
+ else if (g_strcmp0 (type_string, "time-empty") == 0)
+ type = DKP_HISTORY_TYPE_TIME_EMPTY;
+
+ /* something recognised */
+ if (type != DKP_HISTORY_TYPE_UNKNOWN)
+ array = dkp_history_get_data (device->priv->history, type, timespan, resolution);
+
+ /* maybe the device doesn't have any history */
+ if (array == NULL) {
+ error = g_error_new (DKP_DAEMON_ERROR, DKP_DAEMON_ERROR_GENERAL, "device has no history");
+ dbus_g_method_return_error (context, error);
+ goto out;
+ }
+
+ /* copy data to dbus struct */
+ complex = g_ptr_array_sized_new (array->len);
+ for (i=0; i<array->len; i++) {
+ obj = (const DkpHistoryObj *) g_ptr_array_index (array, i);
+ value = g_new0 (GValue, 1);
+ g_value_init (value, DKP_DBUS_STRUCT_UINT_DOUBLE_UINT);
+ g_value_take_boxed (value, dbus_g_type_specialized_construct (DKP_DBUS_STRUCT_UINT_DOUBLE_UINT));
+ dbus_g_type_struct_set (value, 0, obj->time, 1, obj->value, 2, obj->state, -1);
+ g_ptr_array_add (complex, g_value_get_boxed (value));
+ g_free (value);
+ }
+
+ dbus_g_method_return (context, complex);
+out:
+ if (array != NULL) {
+ g_ptr_array_unref (array);
+ }
+ return TRUE;
+}
+
+/**
+ * dkp_device_refresh_internal:
+ *
+ * NOTE: if you're calling this function you have to ensure you're doing the
+ * the changed signals on the right interfaces, although by monitoring
+ * notify::update-time this should be mostly done.
+ **/
+gboolean
+dkp_device_refresh_internal (DkpDevice *device)
+{
+ gboolean ret = FALSE;
+ DkpDeviceClass *klass = DKP_DEVICE_GET_CLASS (device);
+
+ /* not implemented */
+ if (klass->refresh == NULL)
+ goto out;
+
+ /* do the refresh */
+ ret = klass->refresh (device);
+ if (!ret) {
+ egg_debug ("no changes");
+ goto out;
+ }
+
+ /* the first time, print all properties */
+ if (!device->priv->has_ever_refresh) {
+ egg_debug ("added native-path: %s\n", device->priv->native_path);
+ device->priv->has_ever_refresh = TRUE;
+ goto out;
+ }
+out:
+ return ret;
+}
+
+/**
+ * dkp_device_refresh:
+ *
+ * Return %TRUE on success, %FALSE if we failed to refresh or no data
+ **/
+gboolean
+dkp_device_refresh (DkpDevice *device, DBusGMethodInvocation *context)
+{
+ gboolean ret;
+
+ g_return_val_if_fail (DKP_IS_DEVICE (device), FALSE);
+
+ ret = dkp_device_refresh_internal (device);
+ dbus_g_method_return (context);
+ return ret;
+}
+
+/**
+ * dkp_device_get_object_path:
+ **/
+const gchar *
+dkp_device_get_object_path (DkpDevice *device)
+{
+ g_return_val_if_fail (DKP_IS_DEVICE (device), NULL);
+ return device->priv->object_path;
+}
+
+GObject *
+dkp_device_get_native (DkpDevice *device)
+{
+ g_return_val_if_fail (DKP_IS_DEVICE (device), NULL);
+ return device->priv->native;
+}
+
+/**
+ * dkp_device_compute_object_path:
+ **/
+static gchar *
+dkp_device_compute_object_path (DkpDevice *device)
+{
+ gchar *basename;
+ gchar *id;
+ gchar *object_path;
+ const gchar *native_path;
+ const gchar *type;
+ guint i;
+
+ type = dkp_device_type_to_text (device->priv->type);
+ native_path = device->priv->native_path;
+ basename = g_path_get_basename (native_path);
+ id = g_strjoin ("_", type, basename, NULL);
+
+ /* make DBUS valid path */
+ for (i=0; id[i] != '\0'; i++) {
+ if (id[i] == '-')
+ id[i] = '_';
+ if (id[i] == '.')
+ id[i] = 'x';
+ if (id[i] == ':')
+ id[i] = 'o';
+ }
+ object_path = g_build_filename ("/org/freedesktop/DeviceKit/Power/devices", id, NULL);
+
+ g_free (basename);
+ g_free (id);
+
+ return object_path;
+}
+
+/**
+ * dkp_device_register_device:
+ **/
+static gboolean
+dkp_device_register_device (DkpDevice *device)
+{
+ gboolean ret = TRUE;
+
+ device->priv->object_path = dkp_device_compute_object_path (device);
+ egg_debug ("object path = %s", device->priv->object_path);
+ dbus_g_connection_register_g_object (device->priv->system_bus_connection,
+ device->priv->object_path, G_OBJECT (device));
+ device->priv->system_bus_proxy = dbus_g_proxy_new_for_name (device->priv->system_bus_connection,
+ DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS);
+ if (device->priv->system_bus_proxy == NULL) {
+ egg_warning ("proxy invalid");
+ ret = FALSE;
+ }
+ return ret;
+}
+
+/**
+ * dkp_device_perhaps_changed_cb:
+ **/
+static void
+dkp_device_perhaps_changed_cb (GObject *object, GParamSpec *pspec, DkpDevice *device)
+{
+ g_return_if_fail (DKP_IS_DEVICE (device));
+
+ /* don't proxy during coldplug */
+ if (device->priv->during_coldplug)
+ return;
+
+ /* save new history */
+ dkp_history_set_state (device->priv->history, device->priv->state);
+ dkp_history_set_charge_data (device->priv->history, device->priv->percentage);
+ dkp_history_set_rate_data (device->priv->history, device->priv->energy_rate);
+ dkp_history_set_time_full_data (device->priv->history, device->priv->time_to_full);
+ dkp_history_set_time_empty_data (device->priv->history, device->priv->time_to_empty);
+
+ /* The order here matters; we want Device::Changed() before
+ * the DeviceChanged() signal on the main object */
+ egg_debug ("emitting changed on %s", device->priv->native_path);
+ g_signal_emit (device, signals[SIGNAL_CHANGED], 0);
+}
+
+/**
+ * dkp_device_init:
+ **/
+static void
+dkp_device_init (DkpDevice *device)
+{
+ GError *error = NULL;
+
+ device->priv = DKP_DEVICE_GET_PRIVATE (device);
+ device->priv->object_path = NULL;
+ device->priv->system_bus_connection = NULL;
+ device->priv->system_bus_proxy = NULL;
+ device->priv->daemon = NULL;
+ device->priv->native = NULL;
+ device->priv->has_ever_refresh = FALSE;
+ device->priv->during_coldplug = FALSE;
+ device->priv->history = dkp_history_new ();
+
+ device->priv->system_bus_connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);
+ if (device->priv->system_bus_connection == NULL) {
+ egg_error ("error getting system bus: %s", error->message);
+ g_error_free (error);
+ }
+ g_signal_connect (device, "notify::update-time", G_CALLBACK (dkp_device_perhaps_changed_cb), device);
+}
+
+/**
+ * dkp_device_finalize:
+ **/
+static void
+dkp_device_finalize (GObject *object)
+{
+ DkpDevice *device;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (DKP_IS_DEVICE (object));
+
+ device = DKP_DEVICE (object);
+ g_return_if_fail (device->priv != NULL);
+ if (device->priv->native != NULL)
+ g_object_unref (device->priv->native);
+ if (device->priv->daemon != NULL)
+ g_object_unref (device->priv->daemon);
+ g_object_unref (device->priv->history);
+ g_free (device->priv->object_path);
+ g_free (device->priv->vendor);
+ g_free (device->priv->model);
+ g_free (device->priv->serial);
+ g_free (device->priv->native_path);
+ g_free (device->priv->recall_vendor);
+ g_free (device->priv->recall_url);
+
+ G_OBJECT_CLASS (dkp_device_parent_class)->finalize (object);
+}
+
+/**
+ * dkp_device_class_init:
+ **/
+static void
+dkp_device_class_init (DkpDeviceClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ object_class->get_property = dkp_device_get_property;
+ object_class->set_property = dkp_device_set_property;
+ object_class->finalize = dkp_device_finalize;
+
+ g_type_class_add_private (klass, sizeof (DkpDevicePrivate));
+
+ signals[SIGNAL_CHANGED] =
+ g_signal_new ("changed",
+ G_OBJECT_CLASS_TYPE (klass),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
+ 0, NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ dbus_g_object_type_install_info (DKP_TYPE_DEVICE, &dbus_glib_dkp_device_object_info);
+
+ /**
+ * DkpDevice:update-time:
+ */
+ g_object_class_install_property (object_class,
+ PROP_UPDATE_TIME,
+ g_param_spec_uint64 ("update-time",
+ NULL, NULL,
+ 0, G_MAXUINT64, 0,
+ G_PARAM_READWRITE));
+ /**
+ * DkpDevice:vendor:
+ */
+ g_object_class_install_property (object_class,
+ PROP_VENDOR,
+ g_param_spec_string ("vendor",
+ NULL, NULL,
+ NULL,
+ G_PARAM_READWRITE));
+ /**
+ * DkpDevice:model:
+ */
+ g_object_class_install_property (object_class,
+ PROP_MODEL,
+ g_param_spec_string ("model",
+ NULL, NULL,
+ NULL,
+ G_PARAM_READWRITE));
+ /**
+ * DkpDevice:serial:
+ */
+ g_object_class_install_property (object_class,
+ PROP_SERIAL,
+ g_param_spec_string ("serial",
+ NULL, NULL,
+ NULL,
+ G_PARAM_READWRITE));
+ /**
+ * DkpDevice:native-path:
+ */
+ g_object_class_install_property (object_class,
+ PROP_NATIVE_PATH,
+ g_param_spec_string ("native-path",
+ NULL, NULL,
+ NULL,
+ G_PARAM_READWRITE));
+ /**
+ * DkpDevice:power-supply:
+ */
+ g_object_class_install_property (object_class,
+ PROP_POWER_SUPPLY,
+ g_param_spec_boolean ("power-supply",
+ NULL, NULL,
+ FALSE,
+ G_PARAM_READWRITE));
+ /**
+ * DkpDevice:online:
+ */
+ g_object_class_install_property (object_class,
+ PROP_ONLINE,
+ g_param_spec_boolean ("online",
+ NULL, NULL,
+ FALSE,
+ G_PARAM_READWRITE));
+ /**
+ * DkpDevice:is-present:
+ */
+ g_object_class_install_property (object_class,
+ PROP_IS_PRESENT,
+ g_param_spec_boolean ("is-present",
+ NULL, NULL,
+ FALSE,
+ G_PARAM_READWRITE));
+ /**
+ * DkpDevice:is-rechargeable:
+ */
+ g_object_class_install_property (object_class,
+ PROP_IS_RECHARGEABLE,
+ g_param_spec_boolean ("is-rechargeable",
+ NULL, NULL,
+ FALSE,
+ G_PARAM_READWRITE));
+ /**
+ * DkpDevice:has-history:
+ */
+ g_object_class_install_property (object_class,
+ PROP_HAS_HISTORY,
+ g_param_spec_boolean ("has-history",
+ NULL, NULL,
+ FALSE,
+ G_PARAM_READWRITE));
+ /**
+ * DkpDevice:has-statistics:
+ */
+ g_object_class_install_property (object_class,
+ PROP_HAS_STATISTICS,
+ g_param_spec_boolean ("has-statistics",
+ NULL, NULL,
+ FALSE,
+ G_PARAM_READWRITE));
+ /**
+ * DkpDevice:type:
+ */
+ g_object_class_install_property (object_class,
+ PROP_TYPE,
+ g_param_spec_uint ("type",
+ NULL, NULL,
+ DKP_DEVICE_TYPE_UNKNOWN,
+ DKP_DEVICE_TYPE_LAST,
+ DKP_DEVICE_TYPE_UNKNOWN,
+ G_PARAM_READWRITE));
+ /**
+ * DkpDevice:state:
+ */
+ g_object_class_install_property (object_class,
+ PROP_STATE,
+ g_param_spec_uint ("state",
+ NULL, NULL,
+ DKP_DEVICE_STATE_UNKNOWN,
+ DKP_DEVICE_STATE_LAST,
+ DKP_DEVICE_STATE_UNKNOWN,
+ G_PARAM_READWRITE));
+ /**
+ * DkpDevice:technology:
+ */
+ g_object_class_install_property (object_class,
+ PROP_TECHNOLOGY,
+ g_param_spec_uint ("technology",
+ NULL, NULL,
+ DKP_DEVICE_TECHNOLOGY_UNKNOWN,
+ DKP_DEVICE_TECHNOLOGY_LAST,
+ DKP_DEVICE_TECHNOLOGY_UNKNOWN,
+ G_PARAM_READWRITE));
+ /**
+ * DkpDevice:capacity:
+ */
+ g_object_class_install_property (object_class,
+ PROP_CAPACITY,
+ g_param_spec_double ("capacity", NULL, NULL,
+ 0.0, 100.f, 100.0,
+ G_PARAM_READWRITE));
+ /**
+ * DkpDevice:energy:
+ */
+ g_object_class_install_property (object_class,
+ PROP_ENERGY,
+ g_param_spec_double ("energy", NULL, NULL,
+ 0.0, G_MAXDOUBLE, 0.0,
+ G_PARAM_READWRITE));
+ /**
+ * DkpDevice:energy-empty:
+ */
+ g_object_class_install_property (object_class,
+ PROP_ENERGY_EMPTY,
+ g_param_spec_double ("energy-empty", NULL, NULL,
+ 0.0, G_MAXDOUBLE, 0.0,
+ G_PARAM_READWRITE));
+ /**
+ * DkpDevice:energy-full:
+ */
+ g_object_class_install_property (object_class,
+ PROP_ENERGY_FULL,
+ g_param_spec_double ("energy-full", NULL, NULL,
+ 0.0, G_MAXDOUBLE, 0.0,
+ G_PARAM_READWRITE));
+ /**
+ * DkpDevice:energy-full-design:
+ */
+ g_object_class_install_property (object_class,
+ PROP_ENERGY_FULL_DESIGN,
+ g_param_spec_double ("energy-full-design", NULL, NULL,
+ 0.0, G_MAXDOUBLE, 0.0,
+ G_PARAM_READWRITE));
+ /**
+ * DkpDevice:energy-rate:
+ */
+ g_object_class_install_property (object_class,
+ PROP_ENERGY_RATE,
+ g_param_spec_double ("energy-rate", NULL, NULL,
+ 0.0, G_MAXDOUBLE, 0.0,
+ G_PARAM_READWRITE));
+ /**
+ * DkpDevice:voltage:
+ */
+ g_object_class_install_property (object_class,
+ PROP_VOLTAGE,
+ g_param_spec_double ("voltage", NULL, NULL,
+ 0.0, G_MAXDOUBLE, 0.0,
+ G_PARAM_READWRITE));
+ /**
+ * DkpDevice:time-to-empty:
+ */
+ g_object_class_install_property (object_class,
+ PROP_TIME_TO_EMPTY,
+ g_param_spec_int64 ("time-to-empty", NULL, NULL,
+ 0, G_MAXINT64, 0,
+ G_PARAM_READWRITE));
+ /**
+ * DkpDevice:time-to-full:
+ */
+ g_object_class_install_property (object_class,
+ PROP_TIME_TO_FULL,
+ g_param_spec_int64 ("time-to-full", NULL, NULL,
+ 0, G_MAXINT64, 0,
+ G_PARAM_READWRITE));
+ /**
+ * DkpDevice:percentage:
+ */
+ g_object_class_install_property (object_class,
+ PROP_PERCENTAGE,
+ g_param_spec_double ("percentage", NULL, NULL,
+ 0.0, 100.f, 100.0,
+ G_PARAM_READWRITE));
+ /**
+ * DkpDevice:recall-notice:
+ */
+ g_object_class_install_property (object_class,
+ PROP_RECALL_NOTICE,
+ g_param_spec_boolean ("recall-notice",
+ NULL, NULL,
+ FALSE,
+ G_PARAM_READWRITE));
+ /**
+ * DkpDevice:recall-vendor:
+ */
+ g_object_class_install_property (object_class,
+ PROP_RECALL_VENDOR,
+ g_param_spec_string ("recall-vendor",
+ NULL, NULL,
+ NULL,
+ G_PARAM_READWRITE));
+ /**
+ * DkpDevice:recall-url:
+ */
+ g_object_class_install_property (object_class,
+ PROP_RECALL_URL,
+ g_param_spec_string ("recall-url",
+ NULL, NULL,
+ NULL,
+ G_PARAM_READWRITE));
+
+ dbus_g_error_domain_register (DKP_DEVICE_ERROR, NULL, DKP_DEVICE_TYPE_ERROR);
+}
+
+/**
+ * dkp_device_new:
+ **/
+DkpDevice *
+dkp_device_new (void)
+{
+ DkpDevice *device;
+ device = DKP_DEVICE (g_object_new (DKP_TYPE_DEVICE, NULL));
+ return device;
+}
+
+/***************************************************************************
+ *** MAKE CHECK TESTS ***
+ ***************************************************************************/
+#ifdef EGG_TEST
+#include "egg-test.h"
+
+void
+dkp_device_test (gpointer user_data)
+{
+ EggTest *test = (EggTest *) user_data;
+ DkpDevice *device;
+
+ if (!egg_test_start (test, "DkpDevice"))
+ return;
+
+ /************************************************************/
+ egg_test_title (test, "get instance");
+ device = dkp_device_new ();
+ egg_test_assert (test, device != NULL);
+
+ /* unref */
+ g_object_unref (device);
+
+ egg_test_end (test);
+}
+#endif
+