aboutsummaryrefslogtreecommitdiff
path: root/src/service.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/service.c')
-rw-r--r--src/service.c341
1 files changed, 246 insertions, 95 deletions
diff --git a/src/service.c b/src/service.c
index f22d33d..32cec38 100644
--- a/src/service.c
+++ b/src/service.c
@@ -18,15 +18,15 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include "config.h"
-
#include <glib/gi18n.h>
#include <gio/gio.h>
#include <url-dispatcher.h>
+#include "brightness.h"
+#include "dbus-shared.h"
#include "device.h"
#include "device-provider.h"
-#include "ib-brightness-control.h"
+#include "notifier.h"
#include "service.h"
#define BUS_NAME "com.canonical.indicator.power"
@@ -103,7 +103,7 @@ struct _IndicatorPowerServicePrivate
GSettings * settings;
- IbBrightnessControl * brightness_control;
+ IndicatorPowerBrightness * brightness;
guint own_id;
guint actions_export_id;
@@ -120,6 +120,7 @@ struct _IndicatorPowerServicePrivate
GList * devices; /* IndicatorPowerDevice */
IndicatorPowerDeviceProvider * device_provider;
+ IndicatorPowerNotifier * notifier;
};
typedef IndicatorPowerServicePrivate priv_t;
@@ -389,6 +390,8 @@ append_device_to_menu (GMenu * menu, const IndicatorPowerDevice * device, int pr
item = g_menu_item_new (label, NULL);
g_free (label);
+ g_menu_item_set_attribute (item, "x-canonical-type", "s", "com.canonical.indicator.basic");
+
if ((icon = indicator_power_device_get_gicon (device)))
{
GVariant * serialized_icon = g_icon_serialize (icon);
@@ -454,44 +457,17 @@ create_phone_devices_section (IndicatorPowerService * self G_GNUC_UNUSED)
****
***/
-static void
-get_brightness_range (IndicatorPowerService * self, gint * low, gint * high)
-{
- const int max = ib_brightness_control_get_max_value (self->priv->brightness_control);
- *low = max * 0.05; /* 5% minimum -- don't let the screen go completely dark */
- *high = max;
-}
-
-static gdouble
-brightness_to_percentage (IndicatorPowerService * self, int brightness)
-{
- int lo, hi;
- get_brightness_range (self, &lo, &hi);
- return (brightness-lo) / (double)(hi-lo);
-}
-
-static int
-percentage_to_brightness (IndicatorPowerService * self, double percentage)
-{
- int lo, hi;
- get_brightness_range (self, &lo, &hi);
- return (int)(lo + (percentage*(hi-lo)));
-}
-
static GMenuItem *
-create_brightness_menuitem (IndicatorPowerService * self)
+create_brightness_menu_item(void)
{
- int lo, hi;
GMenuItem * item;
- get_brightness_range (self, &lo, &hi);
-
- item = g_menu_item_new (NULL, "indicator.brightness");
- g_menu_item_set_attribute (item, "x-canonical-type", "s", "com.canonical.unity.slider");
- g_menu_item_set_attribute (item, "min-value", "d", brightness_to_percentage (self, lo));
- g_menu_item_set_attribute (item, "max-value", "d", brightness_to_percentage (self, hi));
- g_menu_item_set_attribute (item, "min-icon", "s", "torch-off" );
- g_menu_item_set_attribute (item, "max-icon", "s", "torch-on" );
+ item = g_menu_item_new(NULL, "indicator.brightness");
+ g_menu_item_set_attribute(item, "x-canonical-type", "s", "com.canonical.unity.slider");
+ g_menu_item_set_attribute(item, "min-value", "d", 0.0);
+ g_menu_item_set_attribute(item, "max-value", "d", 1.0);
+ g_menu_item_set_attribute(item, "min-icon", "s", "torch-off" );
+ g_menu_item_set_attribute(item, "max-icon", "s", "torch-on" );
return item;
}
@@ -499,9 +475,8 @@ create_brightness_menuitem (IndicatorPowerService * self)
static GVariant *
action_state_for_brightness (IndicatorPowerService * self)
{
- priv_t * p = self->priv;
- const gint brightness = ib_brightness_control_get_value (p->brightness_control);
- return g_variant_new_double (brightness_to_percentage (self, brightness));
+ IndicatorPowerBrightness * b = self->priv->brightness;
+ return g_variant_new_double(indicator_power_brightness_get_percentage(b));
}
static void
@@ -517,10 +492,9 @@ on_brightness_change_requested (GSimpleAction * action G_GNUC_UNUSED,
gpointer gself)
{
IndicatorPowerService * self = INDICATOR_POWER_SERVICE (gself);
- const gdouble percentage = g_variant_get_double (parameter);
- const int brightness = percentage_to_brightness (self, percentage);
- ib_brightness_control_set_value (self->priv->brightness_control, brightness);
- update_brightness_action_state (self);
+
+ indicator_power_brightness_set_percentage(self->priv->brightness,
+ g_variant_get_double (parameter));
}
static GMenuModel *
@@ -544,21 +518,34 @@ create_desktop_settings_section (IndicatorPowerService * self G_GNUC_UNUSED)
}
static GMenuModel *
-create_phone_settings_section (IndicatorPowerService * self G_GNUC_UNUSED)
+create_phone_settings_section(IndicatorPowerService * self)
{
GMenu * section;
GMenuItem * item;
+ gboolean ab_supported;
- section = g_menu_new ();
+ section = g_menu_new();
- item = create_brightness_menuitem (self);
- g_menu_append_item (section, item);
- update_brightness_action_state (self);
- g_object_unref (item);
+ item = create_brightness_menu_item();
+ g_menu_append_item(section, item);
+ update_brightness_action_state(self);
+ g_object_unref(item);
+
+ g_object_get(self->priv->brightness,
+ "auto-brightness-supported", &ab_supported,
+ NULL);
+
+ if (ab_supported)
+ {
+ item = g_menu_item_new(_("Adjust brightness automatically"), "indicator.auto-brightness");
+ g_menu_item_set_attribute(item, "x-canonical-type", "s", "com.canonical.indicator.switch");
+ g_menu_append_item(section, item);
+ g_object_unref(item);
+ }
- g_menu_append (section, _("Battery settings…"), "indicator.activate-phone-settings");
+ g_menu_append(section, _("Battery settings…"), "indicator.activate-phone-settings");
- return G_MENU_MODEL (section);
+ return G_MENU_MODEL(section);
}
/***
@@ -588,14 +575,14 @@ rebuild_now (IndicatorPowerService * self, guint sections)
struct ProfileMenuInfo * desktop = &p->menus[PROFILE_DESKTOP];
struct ProfileMenuInfo * greeter = &p->menus[PROFILE_DESKTOP_GREETER];
- if (p->conn == NULL) /* we haven't built the menus yet */
- return;
-
if (sections & SECTION_HEADER)
{
g_simple_action_set_state (p->header_action, create_header_state (self));
}
+ if (p->conn == NULL) /* we haven't built the menus yet */
+ return;
+
if (sections & SECTION_DEVICES)
{
rebuild_section (desktop->submenu, 0, create_desktop_devices_section (self, PROFILE_DESKTOP));
@@ -605,7 +592,7 @@ rebuild_now (IndicatorPowerService * self, guint sections)
if (sections & SECTION_SETTINGS)
{
rebuild_section (desktop->submenu, 1, create_desktop_settings_section (self));
- rebuild_section (phone->submenu, 1, create_desktop_settings_section (self));
+ rebuild_section (phone->submenu, 1, create_phone_settings_section (self));
}
}
@@ -615,18 +602,6 @@ rebuild_header_now (IndicatorPowerService * self)
rebuild_now (self, SECTION_HEADER);
}
-static inline void
-rebuild_devices_section_now (IndicatorPowerService * self)
-{
- rebuild_now (self, SECTION_DEVICES);
-}
-
-static inline void
-rebuild_settings_section_now (IndicatorPowerService * self)
-{
- rebuild_now (self, SECTION_SETTINGS);
-}
-
static void
create_menu (IndicatorPowerService * self, int profile)
{
@@ -761,6 +736,28 @@ on_phone_settings_activated (GSimpleAction * a G_GNUC_UNUSED,
****
***/
+static gboolean
+convert_auto_prop_to_state(GBinding * binding G_GNUC_UNUSED,
+ const GValue * from_value,
+ GValue * to_value,
+ gpointer user_data G_GNUC_UNUSED)
+{
+ const gboolean b = g_value_get_boolean(from_value);
+ g_value_set_variant(to_value, g_variant_new_boolean(b));
+ return TRUE;
+}
+
+static gboolean
+convert_auto_state_to_prop(GBinding * binding G_GNUC_UNUSED,
+ const GValue * from_value,
+ GValue * to_value,
+ gpointer user_data G_GNUC_UNUSED)
+{
+ GVariant * v = g_value_get_variant(from_value);
+ g_value_set_boolean(to_value, g_variant_get_boolean(v));
+ return TRUE;
+}
+
static void
init_gactions (IndicatorPowerService * self)
{
@@ -793,6 +790,16 @@ init_gactions (IndicatorPowerService * self)
g_action_map_add_action (G_ACTION_MAP(p->actions), G_ACTION(a));
p->battery_level_action = a;
+ /* add the auto-brightness action */
+ a = g_simple_action_new_stateful("auto-brightness", NULL, g_variant_new_boolean(FALSE));
+ g_object_bind_property_full(p->brightness, "auto-brightness",
+ a, "state",
+ G_BINDING_SYNC_CREATE|G_BINDING_BIDIRECTIONAL,
+ convert_auto_prop_to_state,
+ convert_auto_state_to_prop,
+ NULL, NULL);
+ g_action_map_add_action(G_ACTION_MAP(p->actions), G_ACTION(a));
+
/* add the brightness action */
a = g_simple_action_new_stateful ("brightness", NULL, action_state_for_brightness (self));
g_action_map_add_action (G_ACTION_MAP(p->actions), G_ACTION(a));
@@ -833,6 +840,9 @@ on_bus_acquired (GDBusConnection * connection,
p->conn = g_object_ref (G_OBJECT (connection));
+ /* export the battery properties */
+ indicator_power_notifier_set_bus (p->notifier, connection);
+
/* export the actions */
if ((id = g_dbus_connection_export_action_group (connection,
BUS_PATH,
@@ -854,9 +864,6 @@ on_bus_acquired (GDBusConnection * connection,
g_string_printf (path, "%s/%s", BUS_PATH, menu_names[i]);
- if (menu->menu == NULL)
- create_menu (self, i);
-
if ((id = g_dbus_connection_export_menu_model (connection,
path->str,
G_MENU_MODEL (menu->menu),
@@ -932,16 +939,28 @@ on_devices_changed (IndicatorPowerService * self)
g_clear_object (&p->primary_device);
p->primary_device = indicator_power_service_choose_primary_device (p->devices);
+ /* update the notifier's battery */
+ if ((p->primary_device != NULL) && (indicator_power_device_get_kind(p->primary_device) == UP_DEVICE_KIND_BATTERY))
+ indicator_power_notifier_set_battery (p->notifier, p->primary_device);
+ else
+ indicator_power_notifier_set_battery (p->notifier, NULL);
+
/* update the battery-level action's state */
if (p->primary_device == NULL)
battery_level = 0;
else
- battery_level = (int)(indicator_power_device_get_percentage (p->primary_device) + 0.5);
+ battery_level = (guint32)(indicator_power_device_get_percentage (p->primary_device) + 0.5);
g_simple_action_set_state (p->battery_level_action, g_variant_new_uint32 (battery_level));
rebuild_now (self, SECTION_HEADER | SECTION_DEVICES);
}
+static void
+on_auto_brightness_supported_changed(IndicatorPowerService * self)
+{
+ rebuild_now(self, SECTION_SETTINGS);
+}
+
/***
**** GObject virtual functions
@@ -1013,15 +1032,15 @@ my_dispose (GObject * o)
g_clear_object (&p->settings);
}
+ g_clear_object (&p->notifier);
g_clear_object (&p->brightness_action);
+ g_clear_object (&p->brightness);
g_clear_object (&p->battery_level_action);
g_clear_object (&p->header_action);
g_clear_object (&p->actions);
g_clear_object (&p->conn);
- g_clear_pointer (&p->brightness_control, ib_brightness_control_free);
-
indicator_power_service_set_device_provider (self, NULL);
G_OBJECT_CLASS (indicator_power_service_parent_class)->dispose (o);
@@ -1034,29 +1053,42 @@ my_dispose (GObject * o)
static void
indicator_power_service_init (IndicatorPowerService * self)
{
- priv_t * p = G_TYPE_INSTANCE_GET_PRIVATE (self,
- INDICATOR_TYPE_POWER_SERVICE,
- IndicatorPowerServicePrivate);
+ priv_t * p;
+ int i;
+
+ p = G_TYPE_INSTANCE_GET_PRIVATE (self,
+ INDICATOR_TYPE_POWER_SERVICE,
+ IndicatorPowerServicePrivate);
self->priv = p;
p->cancellable = g_cancellable_new ();
p->settings = g_settings_new ("com.canonical.indicator.power");
- p->brightness_control = ib_brightness_control_new ();
+ p->notifier = indicator_power_notifier_new ();
+
+ p->brightness = indicator_power_brightness_new();
+ g_signal_connect_swapped(p->brightness, "notify::percentage",
+ G_CALLBACK(update_brightness_action_state), self);
init_gactions (self);
g_signal_connect_swapped (p->settings, "changed", G_CALLBACK(rebuild_header_now), self);
- p->own_id = g_bus_own_name (G_BUS_TYPE_SESSION,
- BUS_NAME,
- G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT,
- on_bus_acquired,
- NULL,
- on_name_lost,
- self,
- NULL);
+ for (i=0; i<N_PROFILES; ++i)
+ create_menu(self, i);
+
+ g_signal_connect_swapped(p->brightness, "notify::auto-brightness-supported",
+ G_CALLBACK(on_auto_brightness_supported_changed), self);
+
+ p->own_id = g_bus_own_name(G_BUS_TYPE_SESSION,
+ BUS_NAME,
+ G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT,
+ on_bus_acquired,
+ NULL,
+ on_name_lost,
+ self,
+ NULL);
}
static void
@@ -1117,9 +1149,8 @@ indicator_power_service_set_device_provider (IndicatorPowerService * self,
if (p->device_provider != NULL)
{
- g_signal_handlers_disconnect_by_func (p->device_provider,
- G_CALLBACK(on_devices_changed),
- self);
+ g_signal_handlers_disconnect_by_data (p->device_provider, self);
+
g_clear_object (&p->device_provider);
g_clear_object (&p->primary_device);
@@ -1139,6 +1170,129 @@ indicator_power_service_set_device_provider (IndicatorPowerService * self,
}
}
+/* If a device has multiple batteries and uses only one of them at a time,
+ they should be presented as separate items inside the battery menu,
+ but everywhere else they should be aggregated (bug 880881).
+ Their percentages should be averaged. If any are discharging,
+ the aggregated time remaining should be the maximum of the times
+ for all those that are discharging, plus the sum of the times
+ for all those that are idle. Otherwise, the aggregated time remaining
+ should be the the maximum of the times for all those that are charging. */
+static IndicatorPowerDevice *
+create_totalled_battery_device (const GList * devices)
+{
+ const GList * l;
+ guint n_charged = 0;
+ guint n_charging = 0;
+ guint n_discharging = 0;
+ guint n_batteries = 0;
+ double sum_percent = 0;
+ time_t max_discharge_time = 0;
+ time_t max_charge_time = 0;
+ time_t sum_charged_time = 0;
+ IndicatorPowerDevice * device = NULL;
+
+ for (l=devices; l!=NULL; l=l->next)
+ {
+ const IndicatorPowerDevice * walk = INDICATOR_POWER_DEVICE(l->data);
+
+ if (indicator_power_device_get_kind(walk) == UP_DEVICE_KIND_BATTERY)
+ {
+ const double percent = indicator_power_device_get_percentage (walk);
+ const time_t t = indicator_power_device_get_time (walk);
+ const UpDeviceState state = indicator_power_device_get_state (walk);
+
+ ++n_batteries;
+
+ if (percent > 0.01)
+ sum_percent += percent;
+
+ if (state == UP_DEVICE_STATE_CHARGING)
+ {
+ ++n_charging;
+ max_charge_time = MAX(max_charge_time, t);
+ }
+ else if (state == UP_DEVICE_STATE_DISCHARGING)
+ {
+ ++n_discharging;
+ max_discharge_time = MAX(max_discharge_time, t);
+ }
+ else if (state == UP_DEVICE_STATE_FULLY_CHARGED)
+ {
+ ++n_charged;
+ sum_charged_time += t;
+ }
+ }
+ }
+
+ if (n_batteries > 1)
+ {
+ const double percent = sum_percent / n_batteries;
+ UpDeviceState state;
+ time_t time_left;
+
+ if (n_discharging > 0)
+ {
+ state = UP_DEVICE_STATE_DISCHARGING;
+ time_left = max_discharge_time + sum_charged_time;
+ }
+ else if (n_charging > 0)
+ {
+ state = UP_DEVICE_STATE_CHARGING;
+ time_left = max_charge_time;
+ }
+ else if (n_charged > 0)
+ {
+ state = UP_DEVICE_STATE_FULLY_CHARGED;
+ time_left = 0;
+ }
+ else
+ {
+ state = UP_DEVICE_STATE_UNKNOWN;
+ time_left = 0;
+ }
+
+ device = indicator_power_device_new (NULL,
+ UP_DEVICE_KIND_BATTERY,
+ percent,
+ state,
+ time_left);
+ }
+
+ return device;
+}
+
+/**
+ * If there are multiple UP_DEVICE_KIND_BATTERY devices in the list,
+ * they're merged into a new 'totalled' device representing the sum of them.
+ *
+ * Returns: (element-type IndicatorPowerDevice)(transfer full): a list of devices
+ */
+static GList*
+merge_batteries_together (GList * devices)
+{
+ GList * ret;
+ IndicatorPowerDevice * merged_device;
+
+ if ((merged_device = create_totalled_battery_device (devices)))
+ {
+ GList * l;
+
+ ret = g_list_append (NULL, merged_device);
+
+ for (l=devices; l!=NULL; l=l->next)
+ if (indicator_power_device_get_kind(INDICATOR_POWER_DEVICE(l->data)) != UP_DEVICE_KIND_BATTERY)
+ ret = g_list_append (ret, g_object_ref(l->data));
+ }
+ else /* not enough batteries to merge */
+ {
+ ret = g_list_copy (devices);
+ g_list_foreach (ret, (GFunc)g_object_ref, NULL);
+ }
+
+ return ret;
+}
+
IndicatorPowerDevice *
indicator_power_service_choose_primary_device (GList * devices)
{
@@ -1146,13 +1300,10 @@ indicator_power_service_choose_primary_device (GList * devices)
if (devices != NULL)
{
- GList * tmp;
-
- tmp = g_list_copy (devices);
+ GList * tmp = merge_batteries_together (devices);
tmp = g_list_sort (tmp, device_compare_func);
primary = g_object_ref (tmp->data);
-
- g_list_free (tmp);
+ g_list_free_full (tmp, (GDestroyNotify)g_object_unref);
}
return primary;