aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCharles Kerr <charles.kerr@canonical.com>2014-03-14 14:13:58 +0000
committerCI bot <ps-jenkins@lists.canonical.com>2014-03-14 14:13:58 +0000
commitfe4849e354c850057e2e6c6ff9aaa80d6ab5c815 (patch)
tree023bff8e5b900acf02a0df18111a9dabb00df18f
parent2596b0560ff2aecab8a558e8906236f4f2758f8d (diff)
parentd6159805fc552643902321b3d41d1a0a53594f05 (diff)
downloadayatana-indicator-power-fe4849e354c850057e2e6c6ff9aaa80d6ab5c815.tar.gz
ayatana-indicator-power-fe4849e354c850057e2e6c6ff9aaa80d6ab5c815.tar.bz2
ayatana-indicator-power-fe4849e354c850057e2e6c6ff9aaa80d6ab5c815.zip
Change the implementation of the title text / title accessible text / menuitem text to follow the spec changes in https://wiki.ubuntu.com/Power?action=diff&rev2=44&rev1=43#Title and update the tests accordingly. Fixes: 1234458
-rw-r--r--src/device.c440
-rw-r--r--src/device.h37
-rw-r--r--src/service.c101
-rw-r--r--tests/Makefile.am2
-rw-r--r--tests/test-device.cc169
5 files changed, 487 insertions, 262 deletions
diff --git a/src/device.c b/src/device.c
index 7f1b14f..ed3c399 100644
--- a/src/device.c
+++ b/src/device.c
@@ -37,6 +37,11 @@ struct _IndicatorPowerDevicePrivate
gchar * object_path;
gdouble percentage;
time_t time;
+
+ /* Timestamp of when when we first noticed that upower couldn't estimate
+ the time-remaining field for this device, or 0 if not applicable.
+ This is used when generating the time-remaining string. */
+ GTimer * inestimable;
};
#define INDICATOR_POWER_DEVICE_GET_PRIVATE(o) (INDICATOR_POWER_DEVICE(o)->priv)
@@ -136,6 +141,11 @@ indicator_power_device_init (IndicatorPowerDevice *self)
static void
indicator_power_device_dispose (GObject *object)
{
+ IndicatorPowerDevice * self = INDICATOR_POWER_DEVICE(object);
+ IndicatorPowerDevicePrivate * p = self->priv;
+
+ g_clear_pointer (&p->inestimable, g_timer_destroy);
+
G_OBJECT_CLASS (indicator_power_device_parent_class)->dispose (object);
}
@@ -192,35 +202,54 @@ static void
set_property (GObject * o, guint prop_id, const GValue * value, GParamSpec * pspec)
{
IndicatorPowerDevice * self = INDICATOR_POWER_DEVICE(o);
- IndicatorPowerDevicePrivate * priv = self->priv;
+ IndicatorPowerDevicePrivate * p = self->priv;
switch (prop_id)
{
case PROP_KIND:
- priv->kind = g_value_get_int (value);
+ p->kind = g_value_get_int (value);
break;
case PROP_STATE:
- priv->state = g_value_get_int (value);
+ p->state = g_value_get_int (value);
break;
case PROP_OBJECT_PATH:
- g_free (priv->object_path);
- priv->object_path = g_value_dup_string (value);
+ g_free (p->object_path);
+ p->object_path = g_value_dup_string (value);
break;
case PROP_PERCENTAGE:
- priv->percentage = g_value_get_double (value);
+ p->percentage = g_value_get_double (value);
break;
case PROP_TIME:
- priv->time = g_value_get_uint64(value);
+ p->time = g_value_get_uint64(value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(o, prop_id, pspec);
break;
}
+
+ /**
+ * Check to see if the time-remaining value is estimable.
+ * When it first becomes inestimable, kick off a timer because
+ * we need to track that to generate the appropriate title text.
+ */
+
+ const gboolean is_inestimable = (p->time == 0)
+ && (p->state != UP_DEVICE_STATE_FULLY_CHARGED)
+ && (p->percentage > 0);
+
+ if (!is_inestimable)
+ {
+ g_clear_pointer (&p->inestimable, g_timer_destroy);
+ }
+ else if (p->inestimable == NULL)
+ {
+ p->inestimable = g_timer_new ();
+ }
}
/***
@@ -442,57 +471,6 @@ indicator_power_device_get_gicon (const IndicatorPowerDevice * device)
****
***/
-/* Format time remaining for reading ("H:MM") and speech ("H hours, MM minutes") */
-static void
-get_timestring (guint64 time_secs,
- gchar **readable_timestring,
- gchar **accessible_timestring)
-{
- gint hours;
- gint minutes;
-
- /* Add 0.5 to do rounding */
- minutes = (int) ( ( time_secs / 60.0 ) + 0.5 );
-
- if (minutes == 0)
- {
- *readable_timestring = g_strdup (_("Unknown time"));
- *accessible_timestring = g_strdup (_("Unknown time"));
-
- return;
- }
-
- if (minutes < 60)
- {
- *readable_timestring = g_strdup_printf ("0:%.2i", minutes);
- *accessible_timestring = g_strdup_printf (g_dngettext (GETTEXT_PACKAGE, "%i minute",
- "%i minutes",
- minutes), minutes);
- return;
- }
-
- hours = minutes / 60;
- minutes = minutes % 60;
-
- *readable_timestring = g_strdup_printf ("%i:%.2i", hours, minutes);
-
- if (minutes == 0)
- {
- *accessible_timestring = g_strdup_printf (g_dngettext (GETTEXT_PACKAGE,
- "%i hour",
- "%i hours",
- hours), hours);
- }
- else
- {
- /* TRANSLATOR: "%i %s %i %s" are "%i hours %i minutes"
- * Swap order with "%2$s %2$i %1$s %1$i if needed */
- *accessible_timestring = g_strdup_printf (_("%i %s %i %s"),
- hours, g_dngettext (GETTEXT_PACKAGE, "hour", "hours", hours),
- minutes, g_dngettext (GETTEXT_PACKAGE, "minute", "minutes", minutes));
- }
-}
-
static const gchar *
device_kind_to_localised_string (UpDeviceKind kind)
{
@@ -555,149 +533,287 @@ device_kind_to_localised_string (UpDeviceKind kind)
return text;
}
+/**
+ * The '''brief time-remaining string''' for a component should be:
+ * * the time remaining for it to empty or fully charge,
+ * if estimable, in H:MM format; otherwise
+ * * “estimating…” if the time remaining has been inestimable for
+ * less than 30 seconds; otherwise
+ * * “unknown” if the time remaining has been inestimable for
+ * between 30 seconds and one minute; otherwise
+ * * the empty string.
+ */
static char *
-join_strings (const char * name, const char * time, const char * percent)
+get_brief_time_remaining (const IndicatorPowerDevice * device)
{
- char * str;
- const gboolean have_name = name && *name;
- const gboolean have_time = time && *time;
- const gboolean have_percent = percent && *percent;
-
- if (have_name && have_time && have_percent)
- str = g_strdup_printf (_("%s (%s, %s)"), name, time, percent);
- else if (have_name && have_time)
- str = g_strdup_printf (_("%s (%s)"), name, time);
- else if (have_name && have_percent)
- str = g_strdup_printf (_("%s (%s)"), name, percent);
- else if (have_name)
- str = g_strdup (name);
- else if (have_time && have_percent)
- str = g_strdup_printf (_("(%s, %s)"), time, percent);
- else if (have_time)
- str = g_strdup_printf (_("(%s)"), time);
- else if (have_percent)
- str = g_strdup_printf (_("(%s)"), percent);
- else
- str = g_strdup ("");
+ gchar * str = NULL;
+ const IndicatorPowerDevicePrivate * p = device->priv;
+
+ if (p->time > 0)
+ {
+ int minutes = p->time / 60;
+ const int hours = minutes / 60;
+ minutes %= 60;
+
+ str = g_strdup_printf("%0d:%02d", hours, minutes);
+ }
+ else if (p->inestimable != NULL)
+ {
+ const double elapsed = g_timer_elapsed (p->inestimable, NULL);
+
+ if (elapsed < 30)
+ {
+ str = g_strdup_printf (_("estimating…"));
+ }
+ else if (elapsed < 60)
+ {
+ str = g_strdup_printf (_("unknown"));
+ }
+ }
return str;
}
-static void
-indicator_power_device_get_text (const IndicatorPowerDevice * device,
- gboolean show_time_in_header,
- gboolean show_percentage_in_header,
- gchar ** header,
- gchar ** label,
- gchar ** a11y)
+/**
+ * The '''expanded time-remaining string''' for a component should
+ * be the same as the brief time-remaining string, except that if
+ * the time is estimable:
+ * * if the component is charging, it should be “H:MM to charge”
+ * * if the component is discharging, it should be “H:MM left”.
+ */
+static char*
+get_expanded_time_remaining (const IndicatorPowerDevice * device)
{
- if (!INDICATOR_IS_POWER_DEVICE(device))
+ char * str = NULL;
+ const IndicatorPowerDevicePrivate * p = device->priv;
+
+ if (p->time && ((p->state == UP_DEVICE_STATE_CHARGING) || (p->state == UP_DEVICE_STATE_DISCHARGING)))
+ {
+ int minutes = p->time / 60;
+ const int hours = minutes / 60;
+ minutes %= 60;
+
+ if (p->state == UP_DEVICE_STATE_CHARGING)
+ {
+ str = g_strdup_printf (_("%0d:%02d to charge"), hours, minutes);
+ }
+ else // discharging
+ {
+ str = g_strdup_printf (_("%0d:%02d left"), hours, minutes);
+ }
+ }
+ else
{
- if (a11y != NULL) *a11y = NULL;
- if (label != NULL) *label = NULL;
- if (header != NULL) *header = NULL;
- g_warning ("%s: %p is not an IndicatorPowerDevice", G_STRFUNC, device);
- return;
+ str = get_brief_time_remaining (device);
}
- const time_t time = indicator_power_device_get_time (device);
- const UpDeviceState state = indicator_power_device_get_state (device);
- const UpDeviceKind kind = indicator_power_device_get_kind (device);
- const gchar * device_name = device_kind_to_localised_string (kind);
- const gdouble percentage = indicator_power_device_get_percentage (device);
- char pctstr[32] = { '\0' };
- g_snprintf (pctstr, sizeof(pctstr), "%.0lf%%", percentage);
+ return str;
+}
- GString * terse_time = g_string_new (NULL);
- GString * verbose_time = g_string_new (NULL);
- GString * accessible_time = g_string_new (NULL);
+/**
+ * The '''accessible time-remaining string''' for a component
+ * should be the same as the expanded time-remaining string,
+ * except the H:MM time should be rendered as “''H'' hours ''M'' minutes”,
+ * or just as “''M'' minutes” if the time is less than one hour.
+ */
+static char *
+get_accessible_time_remaining (const IndicatorPowerDevice * device)
+{
+ char * str = NULL;
+ const IndicatorPowerDevicePrivate * p = device->priv;
- if (time > 0)
+ if (p->time && ((p->state == UP_DEVICE_STATE_CHARGING) || (p->state == UP_DEVICE_STATE_DISCHARGING)))
{
- char * readable_timestr = NULL;
- char * accessible_timestr = NULL;
- get_timestring (time, &readable_timestr, &accessible_timestr);
+ int minutes = p->time / 60;
+ const int hours = minutes / 60;
+ minutes %= 60;
- if (state == UP_DEVICE_STATE_CHARGING)
+ if (p->state == UP_DEVICE_STATE_CHARGING)
{
- g_string_assign (terse_time, readable_timestr);
- g_string_printf (verbose_time, _("%s to charge"), readable_timestr);
- g_string_printf (accessible_time, _("%s to charge"), accessible_timestr);
+ if (hours > 0)
+ str = g_strdup_printf (_("%d %s %d %s to charge"),
+ hours, g_dngettext (NULL, "hour", "hours", hours),
+ minutes, g_dngettext (NULL, "minute", "minutes", minutes));
+ else
+ str = g_strdup_printf (_("%d %s to charge"),
+ minutes, g_dngettext (NULL, "minute", "minutes", minutes));
}
- else if ((state == UP_DEVICE_STATE_DISCHARGING) && (time <= (60*60*24)))
+ else // discharging
{
- g_string_assign (terse_time, readable_timestr);
- g_string_printf (verbose_time, _("%s left"), readable_timestr);
- g_string_printf (accessible_time, _("%s left"), accessible_timestr);
+ if (hours > 0)
+ str = g_strdup_printf (_("%d %s %d %s left"),
+ hours, g_dngettext (NULL, "hour", "hours", hours),
+ minutes, g_dngettext (NULL, "minute", "minutes", minutes));
+ else
+ str = g_strdup_printf (_("%d %s left"),
+ minutes, g_dngettext (NULL, "minute", "minutes", minutes));
}
- else
- {
- /* if there's more than 24 hours remaining, we don't show it */
- }
-
- g_free (readable_timestr);
- g_free (accessible_timestr);
}
- else if (state == UP_DEVICE_STATE_FULLY_CHARGED)
+ else
{
- g_string_assign (verbose_time, _("charged"));
- g_string_assign (accessible_time, _("charged"));
+ str = get_brief_time_remaining (device);
}
- else if (percentage > 0)
+
+ return str;
+}
+
+/**
+ * The time is relevant for a device if either (a) the component is charging,
+ * or (b) the component is discharging and the estimated time is less than
+ * 24 hours. (A time greater than 24 hours is probably a mistaken calculation.)
+ */
+static gboolean
+time_is_relevant (const IndicatorPowerDevice * device)
+{
+ const IndicatorPowerDevicePrivate * p = device->priv;
+
+ if (p->state == UP_DEVICE_STATE_CHARGING)
+ return TRUE;
+
+ if ((p->state == UP_DEVICE_STATE_DISCHARGING) && (p->time<(24*60*60)))
+ return TRUE;
+
+ return FALSE;
+}
+
+/**
+ * The menu item for each chargeable component should consist of ...
+ * Text representing the name of the component (“Battery”, “Mouse”,
+ * “UPS”, “Alejandra’s iPod”, etc) and the charge status in brackets:
+ *
+ * * “X (charged)” if it is fully charged and not discharging;
+ * * “X (expanded time-remaining string)” if it is charging,
+ * or discharging with less than 24 hours left;
+ * * “X” if it is discharging with 24 hours or more left.
+ *
+ * The accessible label for the menu item should be the same as the
+ * visible label, except with the accessible time-remaining string
+ * instead of the expanded time-remaining string.
+ */
+static char *
+get_menuitem_text (const IndicatorPowerDevice * device,
+ gboolean accessible)
+{
+ char * str = NULL;
+ const IndicatorPowerDevicePrivate * p = device->priv;
+ const char * kind_str = device_kind_to_localised_string (p->kind);
+
+ if (p->state == UP_DEVICE_STATE_FULLY_CHARGED)
{
- g_string_assign (terse_time, _("estimating…"));
- g_string_assign (verbose_time, _("estimating…"));
- g_string_assign (accessible_time, _("estimating…"));
+ str = g_strdup_printf (_("%s (charged)"), kind_str);
}
else
{
- *pctstr = '\0';
+ char * time_str = NULL;
- if (kind != UP_DEVICE_KIND_LINE_POWER)
+ if (time_is_relevant (device))
{
- g_string_assign (verbose_time, _("not present"));
- g_string_assign (accessible_time, _("not present"));
+ if (accessible)
+ time_str = get_accessible_time_remaining (device);
+ else
+ time_str = get_expanded_time_remaining (device);
}
+
+ if (time_str && *time_str)
+ str = g_strdup_printf (_("%s (%s)"), kind_str, time_str);
+ else
+ str = g_strdup (kind_str);
+
+ g_free (time_str);
}
- if (header != NULL)
- *header = join_strings (NULL,
- show_time_in_header ? terse_time->str : "",
- show_percentage_in_header ? pctstr : "");
+ return str;
+}
- if (label != NULL)
- *label = join_strings (device_name,
- verbose_time->str,
- NULL);
+char *
+indicator_power_device_get_readable_text (const IndicatorPowerDevice * device)
+{
+ g_return_val_if_fail (INDICATOR_IS_POWER_DEVICE(device), NULL);
+
+ return get_menuitem_text (device, FALSE);
+}
- if (a11y != NULL)
- *a11y = join_strings (device_name,
- accessible_time->str,
- pctstr);
+char *
+indicator_power_device_get_accessible_text (const IndicatorPowerDevice * device)
+{
+ g_return_val_if_fail (INDICATOR_IS_POWER_DEVICE(device), NULL);
- g_string_free (terse_time, TRUE);
- g_string_free (verbose_time, TRUE);
- g_string_free (accessible_time, TRUE);
+ return get_menuitem_text (device, TRUE);
}
-gchar *
-indicator_power_device_get_label (const IndicatorPowerDevice * device)
+/**
+ * If the time is relevant and/or “Show Percentage in Menu Bar” is checked,
+ * the icon should be followed by brackets.
+ *
+ * If the time is relevant, the brackets should contain the time-remaining
+ * string for that component.
+ *
+ * If “Show Percentage in Menu Bar” is checked (as it should not be by default),
+ * the brackets should contain the percentage charge for that device.
+ *
+ * If both conditions are true, the time and percentage should be separated by a space.
+ */
+char*
+indicator_power_device_get_readable_title (const IndicatorPowerDevice * device,
+ gboolean want_time,
+ gboolean want_percent)
{
- gchar * label = NULL;
- indicator_power_device_get_text (device, FALSE, FALSE,
- NULL, &label, NULL);
- return label;
+ char * str = NULL;
+ char * time_str = NULL;
+ const IndicatorPowerDevicePrivate * p;
+
+ g_return_val_if_fail (INDICATOR_IS_POWER_DEVICE(device), NULL);
+
+ p = device->priv;
+
+ // if we can't provide time-remaining, turn off the time flag
+ if (want_time && !time_is_relevant (device))
+ want_time = FALSE;
+
+ // if we can't provide percent, turn off the percent flag
+ if (p->percentage < 0.01)
+ want_percent = FALSE;
+
+ // try to build the time-remaining string
+ if (want_time)
+ {
+ time_str = get_brief_time_remaining (device);
+ want_time = time_str && *time_str;
+ }
+
+ if (want_time && want_percent)
+ {
+ str = g_strdup_printf (_("(%s, %.0lf%%)"), time_str, p->percentage);
+ }
+ else if (want_time)
+ {
+ str = g_strdup_printf (_("(%s)"), time_str);
+ }
+ else if (want_percent)
+ {
+ str = g_strdup_printf (_("(%.0lf%%)"), p->percentage);
+ }
+ else
+ {
+ str = NULL;
+ }
+
+ g_free (time_str);
+ return str;
}
-void
-indicator_power_device_get_header (const IndicatorPowerDevice * device,
- gboolean show_time,
- gboolean show_percentage,
- gchar ** header,
- gchar ** a11y)
+/**
+ * Regardless, the accessible name for the whole menu title should be the same
+ * as the accessible name for that thing’s component inside the menu itself.
+ */
+char *
+indicator_power_device_get_accessible_title (const IndicatorPowerDevice * device,
+ gboolean want_time G_GNUC_UNUSED,
+ gboolean want_percent G_GNUC_UNUSED)
{
- indicator_power_device_get_text (device, show_time, show_percentage,
- header, NULL, a11y);
+ g_return_val_if_fail (INDICATOR_IS_POWER_DEVICE(device), NULL);
+
+ return indicator_power_device_get_accessible_text (device);
}
/***
diff --git a/src/device.h b/src/device.h
index 1f395a1..3a10f89 100644
--- a/src/device.h
+++ b/src/device.h
@@ -116,22 +116,27 @@ IndicatorPowerDevice* indicator_power_device_new (const gchar * object_path,
IndicatorPowerDevice* indicator_power_device_new_from_variant (GVariant * variant);
-UpDeviceKind indicator_power_device_get_kind (const IndicatorPowerDevice * device);
-UpDeviceState indicator_power_device_get_state (const IndicatorPowerDevice * device);
-const gchar * indicator_power_device_get_object_path (const IndicatorPowerDevice * device);
-gdouble indicator_power_device_get_percentage (const IndicatorPowerDevice * device);
-time_t indicator_power_device_get_time (const IndicatorPowerDevice * device);
-
-GStrv indicator_power_device_get_icon_names (const IndicatorPowerDevice * device);
-GIcon * indicator_power_device_get_gicon (const IndicatorPowerDevice * device);
-
-gchar * indicator_power_device_get_label (const IndicatorPowerDevice * device);
-
-void indicator_power_device_get_header (const IndicatorPowerDevice * device,
- gboolean show_time,
- gboolean show_percentage,
- gchar ** header,
- gchar ** a11y);
+UpDeviceKind indicator_power_device_get_kind (const IndicatorPowerDevice * device);
+UpDeviceState indicator_power_device_get_state (const IndicatorPowerDevice * device);
+const gchar * indicator_power_device_get_object_path (const IndicatorPowerDevice * device);
+gdouble indicator_power_device_get_percentage (const IndicatorPowerDevice * device);
+time_t indicator_power_device_get_time (const IndicatorPowerDevice * device);
+
+GStrv indicator_power_device_get_icon_names (const IndicatorPowerDevice * device);
+GIcon * indicator_power_device_get_gicon (const IndicatorPowerDevice * device);
+
+
+char * indicator_power_device_get_readable_text (const IndicatorPowerDevice * device);
+
+char * indicator_power_device_get_accessible_text (const IndicatorPowerDevice * device);
+
+char * indicator_power_device_get_readable_title (const IndicatorPowerDevice * device,
+ gboolean want_time,
+ gboolean want_percent);
+
+char * indicator_power_device_get_accessible_title (const IndicatorPowerDevice * device,
+ gboolean want_time,
+ gboolean want_percent);
G_END_DECLS
diff --git a/src/service.c b/src/service.c
index 982a24e..1d8ba3e 100644
--- a/src/service.c
+++ b/src/service.c
@@ -312,21 +312,7 @@ static GVariant *
create_header_state (IndicatorPowerService * self)
{
GVariantBuilder b;
- gchar * label = NULL;
- gchar * a11y = NULL;
- GIcon * icon = NULL;
- priv_t * p = self->priv;
-
- if (p->primary_device != NULL)
- {
- indicator_power_device_get_header (p->primary_device,
- g_settings_get_boolean (p->settings, SETTINGS_SHOW_TIME_S),
- g_settings_get_boolean (p->settings, SETTINGS_SHOW_PERCENTAGE_S),
- &label,
- &a11y);
-
- icon = indicator_power_device_get_gicon (p->primary_device);
- }
+ const priv_t * const p = self->priv;
g_variant_builder_init (&b, G_VARIANT_TYPE("a{sv}"));
@@ -335,24 +321,48 @@ create_header_state (IndicatorPowerService * self)
g_variant_builder_add (&b, "{sv}", "visible",
g_variant_new_boolean (should_be_visible (self)));
- if (label != NULL)
- g_variant_builder_add (&b, "{sv}", "label", g_variant_new_take_string (label));
-
- if (icon != NULL)
+ if (p->primary_device != NULL)
{
- GVariant * v;
+ char * title;
+ GIcon * icon;
+ const gboolean want_time = g_settings_get_boolean (p->settings, SETTINGS_SHOW_TIME_S);
+ const gboolean want_percent = g_settings_get_boolean (p->settings, SETTINGS_SHOW_PERCENTAGE_S);
+
+ title = indicator_power_device_get_readable_title (p->primary_device,
+ want_time,
+ want_percent);
+ if (title)
+ {
+ if (*title)
+ g_variant_builder_add (&b, "{sv}", "label", g_variant_new_take_string (title));
+ else
+ g_free (title);
+ }
- if ((v = g_icon_serialize (icon)))
+ title = indicator_power_device_get_accessible_title (p->primary_device,
+ want_time,
+ want_percent);
+ if (title)
{
- g_variant_builder_add (&b, "{sv}", "icon", v);
- g_variant_unref (v);
+ if (*title)
+ g_variant_builder_add (&b, "{sv}", "accessible-desc", g_variant_new_take_string (title));
+ else
+ g_free (title);
}
- g_object_unref (icon);
- }
+ if ((icon = indicator_power_device_get_gicon (p->primary_device)))
+ {
+ GVariant * serialized_icon = g_icon_serialize (icon);
- if (a11y != NULL)
- g_variant_builder_add (&b, "{sv}", "accessible-desc", g_variant_new_take_string (a11y));
+ if (serialized_icon != NULL)
+ {
+ g_variant_builder_add (&b, "{sv}", "icon", serialized_icon);
+ g_variant_unref (serialized_icon);
+ }
+
+ g_object_unref (icon);
+ }
+ }
return g_variant_builder_end (&b);
}
@@ -365,7 +375,7 @@ create_header_state (IndicatorPowerService * self)
***/
static void
-append_device_to_menu (GMenu * menu, const IndicatorPowerDevice * device)
+append_device_to_menu (GMenu * menu, const IndicatorPowerDevice * device, int profile)
{
const UpDeviceKind kind = indicator_power_device_get_kind (device);
@@ -375,24 +385,31 @@ append_device_to_menu (GMenu * menu, const IndicatorPowerDevice * device)
GMenuItem * item;
GIcon * icon;
- label = indicator_power_device_get_label (device);
- item = g_menu_item_new (label, "indicator.activate-statistics");
+ label = indicator_power_device_get_readable_text (device);
+ item = g_menu_item_new (label, NULL);
g_free (label);
- g_menu_item_set_action_and_target(item, "indicator.activate-statistics", "s",
- indicator_power_device_get_object_path (device));
if ((icon = indicator_power_device_get_gicon (device)))
{
- GVariant * v;
- if ((v = g_icon_serialize (icon)))
+ GVariant * serialized_icon = g_icon_serialize (icon);
+
+ if (serialized_icon != NULL)
{
- g_menu_item_set_attribute_value (item, G_MENU_ATTRIBUTE_ICON, v);
- g_variant_unref (v);
+ g_menu_item_set_attribute_value (item,
+ G_MENU_ATTRIBUTE_ICON,
+ serialized_icon);
+ g_variant_unref (serialized_icon);
}
g_object_unref (icon);
}
+ if (profile == PROFILE_DESKTOP)
+ {
+ g_menu_item_set_action_and_target(item, "indicator.activate-statistics", "s",
+ indicator_power_device_get_object_path (device));
+ }
+
g_menu_append_item (menu, item);
g_object_unref (item);
}
@@ -400,13 +417,13 @@ append_device_to_menu (GMenu * menu, const IndicatorPowerDevice * device)
static GMenuModel *
-create_desktop_devices_section (IndicatorPowerService * self)
+create_desktop_devices_section (IndicatorPowerService * self, int profile)
{
GList * l;
GMenu * menu = g_menu_new ();
for (l=self->priv->devices; l!=NULL; l=l->next)
- append_device_to_menu (menu, l->data);
+ append_device_to_menu (menu, l->data, profile);
return G_MENU_MODEL (menu);
}
@@ -581,8 +598,8 @@ rebuild_now (IndicatorPowerService * self, guint sections)
if (sections & SECTION_DEVICES)
{
- rebuild_section (desktop->submenu, 0, create_desktop_devices_section (self));
- rebuild_section (greeter->submenu, 0, create_desktop_devices_section (self));
+ rebuild_section (desktop->submenu, 0, create_desktop_devices_section (self, PROFILE_DESKTOP));
+ rebuild_section (greeter->submenu, 0, create_desktop_devices_section (self, PROFILE_DESKTOP_GREETER));
}
if (sections & SECTION_SETTINGS)
@@ -633,12 +650,12 @@ create_menu (IndicatorPowerService * self, int profile)
break;
case PROFILE_DESKTOP:
- sections[n++] = create_desktop_devices_section (self);
+ sections[n++] = create_desktop_devices_section (self, PROFILE_DESKTOP);
sections[n++] = create_desktop_settings_section (self);
break;
case PROFILE_DESKTOP_GREETER:
- sections[n++] = create_desktop_devices_section (self);
+ sections[n++] = create_desktop_devices_section (self, PROFILE_DESKTOP_GREETER);
break;
}
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 5c7d802..47b3e84 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -18,7 +18,7 @@ nodist_libgtest_a_SOURCES = \
$(GTEST_SOURCE)/src/gtest-all.cc \
$(GTEST_SOURCE)/src/gtest_main.cc
-AM_CPPFLAGS = $(GTEST_CPPFLAGS) -I${top_srcdir}/src -Wall -Werror
+AM_CPPFLAGS = $(GTEST_CPPFLAGS) -I${top_srcdir}/src -Wall -Werror -std=c++11
AM_CXXFLAGS = $(GTEST_CXXFLAGS)
###
diff --git a/tests/test-device.cc b/tests/test-device.cc
index 2762d4a..4d4a89f 100644
--- a/tests/test-device.cc
+++ b/tests/test-device.cc
@@ -72,11 +72,8 @@ class DeviceTest : public ::testing::Test
void check_label (const IndicatorPowerDevice * device,
const char * expected_label)
{
- char * label;
-
- label = indicator_power_device_get_label (device);
+ char * label = indicator_power_device_get_readable_text (device);
EXPECT_STREQ (expected_label, label);
-
g_free (label);
}
@@ -86,31 +83,39 @@ class DeviceTest : public ::testing::Test
const char * expected_percent,
const char * expected_a11y)
{
- char * label;
- char * a11y;
-
- indicator_power_device_get_header (device, true, true, &label, &a11y);
- EXPECT_STREQ (expected_time_and_percent, label);
- EXPECT_STREQ (expected_a11y, a11y);
- g_free (label);
- g_free (a11y);
-
- indicator_power_device_get_header (device, true, false, &label, &a11y);
- EXPECT_STREQ (expected_time, label);
- EXPECT_STREQ (expected_a11y, a11y);
- g_free (label);
- g_free (a11y);
-
- indicator_power_device_get_header (device, false, true, &label, &a11y);
- EXPECT_STREQ (expected_percent, label);
- EXPECT_STREQ (expected_a11y, a11y);
- g_free (label);
- g_free (a11y);
-
- indicator_power_device_get_header (device, false, false, &label, &a11y);
- ASSERT_TRUE (!label || !*label);
- EXPECT_STREQ (expected_a11y, a11y);
- g_free (label);
+ char * a11y = NULL;
+ char * title = NULL;
+
+ title = indicator_power_device_get_readable_title (device, true, true);
+ if (expected_time_and_percent)
+ EXPECT_STREQ (expected_time_and_percent, title);
+ else
+ EXPECT_EQ(NULL, title);
+ g_free (title);
+
+ title = indicator_power_device_get_readable_title (device, true, false);
+ if (expected_time)
+ EXPECT_STREQ (expected_time, title);
+ else
+ EXPECT_EQ(NULL, title);
+ g_free (title);
+
+ title = indicator_power_device_get_readable_title (device, false, true);
+ if (expected_percent)
+ EXPECT_STREQ (expected_percent, title);
+ else
+ EXPECT_EQ(NULL, title);
+ g_free (title);
+
+ title = indicator_power_device_get_readable_title (device, false, false);
+ EXPECT_EQ(NULL, title);
+ g_free (title);
+
+ a11y = indicator_power_device_get_accessible_title (device, false, false);
+ if (expected_a11y)
+ EXPECT_STREQ (expected_a11y, a11y);
+ else
+ EXPECT_EQ(NULL, a11y);
g_free (a11y);
}
};
@@ -481,14 +486,16 @@ TEST_F(DeviceTest, Labels)
g_setenv ("LANG", "en_US.UTF-8", TRUE);
// bad args: NULL device
- log_count_ipower_expected += 5;
+ log_count_ipower_expected++;
check_label (NULL, NULL);
+ log_count_ipower_expected += 5;
check_header (NULL, NULL, NULL, NULL, NULL);
// bad args: a GObject that isn't a device
- log_count_ipower_expected += 5;
GObject * o = G_OBJECT(g_cancellable_new());
+ log_count_ipower_expected++;
check_label ((IndicatorPowerDevice*)o, NULL);
+ log_count_ipower_expected += 5;
check_header (NULL, NULL, NULL, NULL, NULL);
g_object_unref (o);
@@ -509,7 +516,7 @@ TEST_F(DeviceTest, Labels)
check_header (device, "(1:01, 50%)",
"(1:01)",
"(50%)",
- "Battery (1 hour 1 minute to charge, 50%)");
+ "Battery (1 hour 1 minute to charge)");
// discharging, < 12 hours left
g_object_set (o, INDICATOR_POWER_DEVICE_KIND, UP_DEVICE_KIND_BATTERY,
@@ -521,7 +528,7 @@ TEST_F(DeviceTest, Labels)
check_header (device, "(1:01, 50%)",
"(1:01)",
"(50%)",
- "Battery (1 hour 1 minute left, 50%)");
+ "Battery (1 hour 1 minute left)");
// discharging, > 24 hours left
// we don't show the clock time when > 24 hours discharging
@@ -532,9 +539,9 @@ TEST_F(DeviceTest, Labels)
NULL);
check_label (device, "Battery");
check_header (device, "(50%)",
- "",
+ NULL,
"(50%)",
- "Battery (50%)");
+ "Battery");
// fully charged
g_object_set (o, INDICATOR_POWER_DEVICE_KIND, UP_DEVICE_KIND_BATTERY,
@@ -544,9 +551,9 @@ TEST_F(DeviceTest, Labels)
NULL);
check_label (device, "Battery (charged)");
check_header (device, "(100%)",
- "",
+ NULL,
"(100%)",
- "Battery (charged, 100%)");
+ "Battery (charged)");
// percentage but no time estimate
g_object_set (o, INDICATOR_POWER_DEVICE_KIND, UP_DEVICE_KIND_BATTERY,
@@ -558,7 +565,7 @@ TEST_F(DeviceTest, Labels)
check_header (device, "(estimating…, 50%)",
"(estimating…)",
"(50%)",
- "Battery (estimating…, 50%)");
+ "Battery (estimating…)");
// no percentage, no time estimate
g_object_set (o, INDICATOR_POWER_DEVICE_KIND, UP_DEVICE_KIND_BATTERY,
@@ -566,8 +573,8 @@ TEST_F(DeviceTest, Labels)
INDICATOR_POWER_DEVICE_PERCENTAGE, 0.0,
INDICATOR_POWER_DEVICE_TIME, guint64(0),
NULL);
- check_label (device, "Battery (not present)");
- check_header (device, "", "", "", "Battery (not present)");
+ check_label (device, "Battery");
+ check_header (device, NULL, NULL, NULL, "Battery");
// power line
g_object_set (o, INDICATOR_POWER_DEVICE_KIND, UP_DEVICE_KIND_LINE_POWER,
@@ -576,7 +583,7 @@ TEST_F(DeviceTest, Labels)
INDICATOR_POWER_DEVICE_TIME, guint64(0),
NULL);
check_label (device, "AC Adapter");
- check_header (device, "", "", "", "AC Adapter");
+ check_header (device, NULL, NULL, NULL, "AC Adapter");
// cleanup
g_object_unref(o);
@@ -584,6 +591,84 @@ TEST_F(DeviceTest, Labels)
g_free (real_lang);
}
+
+TEST_F(DeviceTest, Inestimable___this_takes_80_seconds)
+{
+ // set our language so that i18n won't break these tests
+ auto real_lang = g_strdup(g_getenv ("LANG"));
+ g_setenv ("LANG", "en_US.UTF-8", true);
+
+ // set up the main loop
+ auto loop = g_main_loop_new (nullptr, false);
+ auto loop_quit_sourcefunc = [](gpointer l){
+ g_main_loop_quit(static_cast<GMainLoop*>(l));
+ return G_SOURCE_REMOVE;
+ };
+
+ auto device = INDICATOR_POWER_DEVICE (g_object_new (INDICATOR_POWER_DEVICE_TYPE, nullptr));
+ auto o = G_OBJECT(device);
+
+ // percentage but no time estimate
+ auto timer = g_timer_new ();
+ g_object_set (o, INDICATOR_POWER_DEVICE_KIND, UP_DEVICE_KIND_BATTERY,
+ INDICATOR_POWER_DEVICE_STATE, UP_DEVICE_STATE_DISCHARGING,
+ INDICATOR_POWER_DEVICE_PERCENTAGE, 50.0,
+ INDICATOR_POWER_DEVICE_TIME, guint64(0),
+ nullptr);
+
+ /*
+ * “estimating…” if the time remaining has been inestimable for
+ * less than 30 seconds; otherwise “unknown” if the time remaining
+ * has been inestimable for between 30 seconds and one minute;
+ * otherwise the empty string.
+ */
+ for (;;)
+ {
+ g_timeout_add_seconds (1, loop_quit_sourcefunc, loop);
+ g_main_loop_run (loop);
+
+ const auto elapsed = g_timer_elapsed (timer, nullptr);
+
+ if (elapsed < 30)
+ {
+ check_label (device, "Battery (estimating…)");
+ check_header (device, "(estimating…, 50%)",
+ "(estimating…)",
+ "(50%)",
+ "Battery (estimating…)");
+ }
+ else if (elapsed < 60)
+ {
+ check_label (device, "Battery (unknown)");
+ check_header (device, "(unknown, 50%)",
+ "(unknown)",
+ "(50%)",
+ "Battery (unknown)");
+ }
+ else if (elapsed < 80)
+ {
+ check_label (device, "Battery");
+ check_header (device, "(50%)",
+ NULL,
+ "(50%)",
+ "Battery");
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ g_main_loop_unref (loop);
+
+ // cleanup
+ g_timer_destroy (timer);
+ g_object_unref (o);
+ g_setenv ("LANG", real_lang, TRUE);
+ g_free (real_lang);
+}
+
+
/* The menu title should tell you at a glance what you need to know most: what
device will lose power soonest (and optionally when), or otherwise which
device will take longest to charge (and optionally how long it will take). */
@@ -645,10 +730,12 @@ TEST_F(DeviceTest, ChoosePrimary)
INDICATOR_POWER_DEVICE_PERCENTAGE, tests[j].percentage,
NULL);
ASSERT_EQ (a, indicator_power_service_choose_primary_device(device_list));
+ g_object_unref (G_OBJECT(a));
/* reverse the list to check that list order doesn't matter */
device_list = g_list_reverse (device_list);
ASSERT_EQ (a, indicator_power_service_choose_primary_device(device_list));
+ g_object_unref (G_OBJECT(a));
}
}