/* A simple Device structure used internally by indicator-power Copyright 2012 Canonical Ltd. Authors: Charles Kerr This library is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 3.0 as published by the Free Software Foundation. This library 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 version 3.0 for more details. You should have received a copy of the GNU General Public License along with this library. If not, see . */ #include "device.h" struct _IndicatorPowerDevicePrivate { UpDeviceKind kind; UpDeviceState state; gchar * object_path; gchar * icon; gdouble percentage; time_t time; }; #define INDICATOR_POWER_DEVICE_GET_PRIVATE(o) (INDICATOR_POWER_DEVICE(o)->priv) /* Properties */ /* Enum for the properties so that they can be quickly found and looked up. */ enum { PROP_0, PROP_KIND, PROP_STATE, PROP_OBJECT_PATH, PROP_ICON, PROP_PERCENTAGE, PROP_TIME }; /* GObject stuff */ static void indicator_power_device_class_init (IndicatorPowerDeviceClass *klass); static void indicator_power_device_init (IndicatorPowerDevice *self); static void indicator_power_device_dispose (GObject *object); static void indicator_power_device_finalize (GObject *object); static void set_property (GObject*, guint prop_id, const GValue*, GParamSpec* ); static void get_property (GObject*, guint prop_id, GValue*, GParamSpec* ); /* LCOV_EXCL_START */ G_DEFINE_TYPE (IndicatorPowerDevice, indicator_power_device, G_TYPE_OBJECT); /* LCOV_EXCL_STOP */ static void indicator_power_device_class_init (IndicatorPowerDeviceClass *klass) { GParamSpec * pspec; GObjectClass *object_class = G_OBJECT_CLASS (klass); g_type_class_add_private (klass, sizeof (IndicatorPowerDevicePrivate)); object_class->dispose = indicator_power_device_dispose; object_class->finalize = indicator_power_device_finalize; object_class->set_property = set_property; object_class->get_property = get_property; pspec = g_param_spec_int (INDICATOR_POWER_DEVICE_KIND, "kind", "The device's UpDeviceKind", UP_DEVICE_KIND_UNKNOWN, UP_DEVICE_KIND_LAST, UP_DEVICE_KIND_UNKNOWN, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_KIND, pspec); pspec = g_param_spec_int (INDICATOR_POWER_DEVICE_STATE, "state", "The device's UpDeviceState", UP_DEVICE_STATE_UNKNOWN, UP_DEVICE_STATE_LAST, UP_DEVICE_STATE_UNKNOWN, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_STATE, pspec); pspec = g_param_spec_string (INDICATOR_POWER_DEVICE_OBJECT_PATH, "object path", "The device's DBus object path", NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_OBJECT_PATH, pspec); pspec = g_param_spec_string (INDICATOR_POWER_DEVICE_ICON, "icon", "The device's icon", NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_ICON, pspec); pspec = g_param_spec_double (INDICATOR_POWER_DEVICE_PERCENTAGE, "percentage", "percent charged", 0.0, 100.0, 0.0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_PERCENTAGE, pspec); pspec = g_param_spec_uint64 (INDICATOR_POWER_DEVICE_TIME, "time", "time left", 0, G_MAXUINT64, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_TIME, pspec); } /* Initialize an instance */ static void indicator_power_device_init (IndicatorPowerDevice *self) { IndicatorPowerDevicePrivate * priv; priv = G_TYPE_INSTANCE_GET_PRIVATE (self, INDICATOR_POWER_DEVICE_TYPE, IndicatorPowerDevicePrivate); priv->kind = UP_DEVICE_KIND_UNKNOWN; priv->state = UP_DEVICE_STATE_UNKNOWN; priv->object_path = NULL; priv->icon = NULL; priv->percentage = 0.0; priv->time = 0; self->priv = priv; } static void indicator_power_device_dispose (GObject *object) { G_OBJECT_CLASS (indicator_power_device_parent_class)->dispose (object); } static void indicator_power_device_finalize (GObject *object) { IndicatorPowerDevice * self = INDICATOR_POWER_DEVICE(object); IndicatorPowerDevicePrivate * priv = self->priv; g_clear_pointer (&priv->object_path, g_free); g_clear_pointer (&priv->icon, g_free); } /*** **** ***/ static void get_property (GObject * o, guint prop_id, GValue * value, GParamSpec * pspec) { IndicatorPowerDevice * self = INDICATOR_POWER_DEVICE(o); IndicatorPowerDevicePrivate * priv = self->priv; switch (prop_id) { case PROP_KIND: g_value_set_int (value, priv->kind); break; case PROP_STATE: g_value_set_int (value, priv->state); break; case PROP_OBJECT_PATH: g_value_set_string (value, priv->object_path); break; case PROP_ICON: g_value_set_string (value, priv->icon); break; case PROP_PERCENTAGE: g_value_set_double (value, priv->percentage); break; case PROP_TIME: g_value_set_uint64 (value, priv->time); break; } } static void set_property (GObject * o, guint prop_id, const GValue * value, GParamSpec * pspec) { IndicatorPowerDevice * self = INDICATOR_POWER_DEVICE(o); IndicatorPowerDevicePrivate * priv = self->priv; switch (prop_id) { case PROP_KIND: priv->kind = g_value_get_int (value); break; case PROP_STATE: priv->state = g_value_get_int (value); break; case PROP_OBJECT_PATH: g_free (priv->object_path); priv->object_path = g_value_dup_string (value); break; case PROP_ICON: g_free (priv->icon); priv->icon = g_value_dup_string (value); break; case PROP_PERCENTAGE: priv->percentage = g_value_get_double (value); break; case PROP_TIME: priv->time = g_value_get_uint64(value); break; } } /*** **** Accessors ***/ UpDeviceKind indicator_power_device_get_kind (const IndicatorPowerDevice * device) { /* LCOV_EXCL_START */ g_return_val_if_fail (INDICATOR_IS_POWER_DEVICE(device), UP_DEVICE_KIND_UNKNOWN); /* LCOV_EXCL_STOP */ return device->priv->kind; } UpDeviceState indicator_power_device_get_state (const IndicatorPowerDevice * device) { /* LCOV_EXCL_START */ g_return_val_if_fail (INDICATOR_IS_POWER_DEVICE(device), UP_DEVICE_STATE_UNKNOWN); /* LCOV_EXCL_STOP */ return device->priv->state; } const gchar * indicator_power_device_get_object_path (const IndicatorPowerDevice * device) { /* LCOV_EXCL_START */ g_return_val_if_fail (INDICATOR_IS_POWER_DEVICE(device), NULL); /* LCOV_EXCL_STOP */ return device->priv->object_path; } const gchar * indicator_power_device_get_icon (const IndicatorPowerDevice * device) { /* LCOV_EXCL_START */ g_return_val_if_fail (INDICATOR_IS_POWER_DEVICE(device), UP_DEVICE_KIND_UNKNOWN); /* LCOV_EXCL_STOP */ return device->priv->icon; } gdouble indicator_power_device_get_percentage (const IndicatorPowerDevice * device) { /* LCOV_EXCL_START */ g_return_val_if_fail (INDICATOR_IS_POWER_DEVICE(device), 0.0); /* LCOV_EXCL_STOP */ return device->priv->percentage; } time_t indicator_power_device_get_time (const IndicatorPowerDevice * device) { /* LCOV_EXCL_START */ g_return_val_if_fail (INDICATOR_IS_POWER_DEVICE(device), (time_t)0); /* LCOV_EXCL_STOP */ return device->priv->time; } /*** **** **** ***/ /* taken from GSD's power plugin, (c) Richard Hughes and licensed GPL >=2 */ static const gchar * gpm_upower_get_device_icon_suffix (gdouble percentage) { if (percentage < 10) return "caution"; if (percentage < 30) return "low"; if (percentage < 60) return "good"; return "full"; } /* taken from GSD's power plugin, (c) Richard Hughes and licensed GPL >=2 */ static const gchar * gpm_upower_get_device_icon_index (gdouble percentage) { if (percentage < 10) return "000"; if (percentage < 30) return "020"; if (percentage < 50) return "040"; if (percentage < 70) return "060"; if (percentage < 90) return "080"; return "100"; } /** indicator_power_device_get_icon_names: @device: #IndicatorPowerDevice to generate the icon names from Based on GSD's power plugin, (c) Richard Hughes and licensed GPL >= 2. It differs in these ways: (1) all charging batteries use the same icon regardless of progress: (2) discharging batteries are keyed off of time left, rather than percentage left, s.t. <= 30 minutes remaining gives the 'caution' icon. Return value: (array zero-terminated=1) (transfer full): a GStrv of icon names suitable for passing to g_themed_icon_new_from_names(). Free with g_strfreev() when done. */ GStrv indicator_power_device_get_icon_names (const IndicatorPowerDevice * device) { char ** ret = NULL; const gchar *suffix_str; const gchar *index_str; /* LCOV_EXCL_START */ g_return_val_if_fail (INDICATOR_IS_POWER_DEVICE(device), UP_DEVICE_KIND_UNKNOWN); /* LCOV_EXCL_STOP */ gdouble percentage = indicator_power_device_get_percentage (device); const UpDeviceKind kind = indicator_power_device_get_kind (device); const UpDeviceState state = indicator_power_device_get_state (device); const char * kind_str = kind_str = up_device_kind_to_string (kind); /* get correct icon prefix */ GString * filename = g_string_new (NULL); /* get the icon from some simple rules */ if (kind == UP_DEVICE_KIND_LINE_POWER) { g_string_append (filename, "ac-adapter-symbolic;"); g_string_append (filename, "ac-adapter;"); } else if (kind == UP_DEVICE_KIND_MONITOR) { g_string_append (filename, "gpm-monitor-symbolic;"); g_string_append (filename, "gpm-monitor;"); } else switch (state) { case UP_DEVICE_STATE_EMPTY: g_string_append (filename, "battery-empty-symbolic;"); g_string_append_printf (filename, "gpm-%s-empty;", kind_str); g_string_append_printf (filename, "gpm-%s-000;", kind_str); g_string_append (filename, "battery-empty;"); break; case UP_DEVICE_STATE_FULLY_CHARGED: g_string_append (filename, "battery-full-charged-symbolic;"); g_string_append (filename, "battery-full-charging-symbolic;"); g_string_append_printf (filename, "gpm-%s-full;", kind_str); g_string_append_printf (filename, "gpm-%s-100;", kind_str); g_string_append (filename, "battery-full-charged;"); g_string_append (filename, "battery-full-charging;"); break; case UP_DEVICE_STATE_CHARGING: case UP_DEVICE_STATE_PENDING_CHARGE: /* When charging, always use the same icon regardless of percentage. */ percentage = 0; suffix_str = gpm_upower_get_device_icon_suffix (percentage); index_str = gpm_upower_get_device_icon_index (percentage); g_string_append_printf (filename, "battery-%s-charging-symbolic;", suffix_str); g_string_append_printf (filename, "gpm-%s-%s-charging;", kind_str, index_str); g_string_append_printf (filename, "battery-%s-charging;", suffix_str); break; case UP_DEVICE_STATE_DISCHARGING: case UP_DEVICE_STATE_PENDING_DISCHARGE: { /* Don't show the caution/red icons unless we have <=30 min left. Themes use the caution color when the percentage is 0% or 20%, so if we have >30 min left, use 30% as the icon's percentage floor */ if (indicator_power_device_get_time (device) > (30*60)) percentage = MAX(percentage, 30); suffix_str = gpm_upower_get_device_icon_suffix (percentage); index_str = gpm_upower_get_device_icon_index (percentage); g_string_append_printf (filename, "battery-%s-symbolic;", suffix_str); g_string_append_printf (filename, "gpm-%s-%s;", kind_str, index_str); g_string_append_printf (filename, "battery-%s;", suffix_str); break; } default: g_string_append (filename, "battery-missing-symbolic;"); g_string_append (filename, "gpm-battery-missing;"); g_string_append (filename, "battery-missing;"); } ret = g_strsplit (filename->str, ";", -1); g_string_free (filename, TRUE); return ret; } /** indicator_power_device_get_gicon: @device: #IndicatorPowerDevice to generate the icon names from A convenience function to call g_themed_icon_new_from_names() with the names returned by indicator_power_device_get_icon_names() Return value: (transfer full): A themed GIcon */ GIcon * indicator_power_device_get_gicon (const IndicatorPowerDevice * device) { GStrv names = indicator_power_device_get_icon_names (device); GIcon * icon = g_themed_icon_new_from_names (names, -1); g_strfreev (names); return icon; } #if 0 static const gchar * get_icon_percentage_for_status (const gchar *status) { if (g_strcmp0 (status, "caution") == 0) return "000"; else if (g_strcmp0 (status, "low") == 0) return "040"; else if (g_strcmp0 (status, "good") == 0) return "080"; else return "100"; } static GIcon* build_battery_icon (UpDeviceState state, gchar *suffix_str) { GIcon *gicon; GString *filename; gchar **iconnames; filename = g_string_new (NULL); if (state == UP_DEVICE_STATE_FULLY_CHARGED) { g_string_append (filename, "battery-charged;"); g_string_append (filename, "battery-full-charged-symbolic;"); g_string_append (filename, "battery-full-charged;"); g_string_append (filename, "gpm-battery-charged;"); g_string_append (filename, "gpm-battery-100-charging;"); } else if (state == UP_DEVICE_STATE_CHARGING) { g_string_append (filename, "battery-000-charging;"); g_string_append (filename, "battery-caution-charging-symbolic;"); g_string_append (filename, "battery-caution-charging;"); g_string_append (filename, "gpm-battery-000-charging;"); } else if (state == UP_DEVICE_STATE_DISCHARGING) { const gchar *percentage = get_icon_percentage_for_status (suffix_str); g_string_append_printf (filename, "battery-%s;", suffix_str); g_string_append_printf (filename, "battery-%s-symbolic;", suffix_str); g_string_append_printf (filename, "battery-%s;", percentage); g_string_append_printf (filename, "gpm-battery-%s;", percentage); } iconnames = g_strsplit (filename->str, ";", -1); gicon = g_themed_icon_new_from_names (iconnames, -1); g_strfreev (iconnames); g_string_free (filename, TRUE); return gicon; } static GIcon* get_device_icon (UpDeviceKind kind, UpDeviceState state, guint64 time_sec, const gchar *device_icon) { GIcon *gicon = NULL; if (kind == UP_DEVICE_KIND_BATTERY && (state == UP_DEVICE_STATE_FULLY_CHARGED || state == UP_DEVICE_STATE_CHARGING || state == UP_DEVICE_STATE_DISCHARGING)) { if (state == UP_DEVICE_STATE_FULLY_CHARGED || state == UP_DEVICE_STATE_CHARGING) { gicon = build_battery_icon (state, NULL); } else if (state == UP_DEVICE_STATE_DISCHARGING) { if ((time_sec > 60 * 30) && /* more than 30 minutes left */ (g_strrstr (device_icon, "000") || g_strrstr (device_icon, "020") || g_strrstr (device_icon, "caution"))) /* the icon is red */ { gicon = build_battery_icon (state, "low"); } } } if (gicon == NULL) gicon = g_icon_new_for_string (device_icon, NULL); return gicon; } #endif /*** **** Instantiation ***/ IndicatorPowerDevice * indicator_power_device_new (const gchar * object_path, UpDeviceKind kind, const gchar * icon_path, gdouble percentage, UpDeviceState state, time_t timestamp) { GObject * o = g_object_new (INDICATOR_POWER_DEVICE_TYPE, INDICATOR_POWER_DEVICE_KIND, kind, INDICATOR_POWER_DEVICE_STATE, state, INDICATOR_POWER_DEVICE_OBJECT_PATH, object_path, INDICATOR_POWER_DEVICE_ICON, icon_path, INDICATOR_POWER_DEVICE_PERCENTAGE, percentage, INDICATOR_POWER_DEVICE_TIME, (guint64)timestamp, NULL); return INDICATOR_POWER_DEVICE(o); } IndicatorPowerDevice * indicator_power_device_new_from_variant (GVariant * v) { UpDeviceKind kind = UP_DEVICE_KIND_UNKNOWN; UpDeviceState state = UP_DEVICE_STATE_UNKNOWN; const gchar * icon = NULL; const gchar * object_path = NULL; gdouble percentage = 0; guint64 time = 0; g_variant_get (v, "(&su&sdut)", &object_path, &kind, &icon, &percentage, &state, &time); return indicator_power_device_new (object_path, kind, icon, percentage, state, time); }