/*
* Copyright 2014 Canonical Ltd.
* Copyright 2023 Robert Tari
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3, as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranties of
* MERCHANTABILITY, SATISFACTORY QUALITY, 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, see .
*
* Authors:
* Charles Kerr
* Robert Tari
*/
#include "dbus-shared.h"
#include "device-provider-mock.h"
#include "device-provider-upower.h"
#include "dbus-testing.h"
#include "service.h"
#include "testing.h"
#include
/**
*** GObject Properties
**/
enum
{
PROP_0,
PROP_SERVICE,
LAST_PROP
};
static GParamSpec * properties[LAST_PROP];
/**
***
**/
typedef struct
{
GDBusConnection * bus;
DbusTesting * skeleton;
IndicatorPowerService * service;
IndicatorPowerDevice * battery_mock;
gpointer provider_mock;
gpointer provider_upower;
}
IndicatorPowerTestingPrivate;
typedef IndicatorPowerTestingPrivate priv_t;
G_DEFINE_TYPE_WITH_PRIVATE(IndicatorPowerTesting,
indicator_power_testing,
G_TYPE_OBJECT)
#define get_priv(o) ((priv_t*)indicator_power_testing_get_instance_private(o))
/***
****
***/
static void
update_device_provider (IndicatorPowerTesting * self)
{
priv_t * const p = get_priv(self);
IndicatorPowerDeviceProvider * device_provider;
device_provider = dbus_testing_get_mock_battery_enabled(p->skeleton)
? p->provider_mock
: p->provider_upower;
indicator_power_service_set_device_provider(p->service, device_provider);
}
static void
set_bus(IndicatorPowerTesting * self, GDBusConnection * bus)
{
priv_t * p;
GDBusInterfaceSkeleton * skel;
g_return_if_fail(INDICATOR_IS_POWER_TESTING(self));
g_return_if_fail((bus == NULL) || G_IS_DBUS_CONNECTION(bus));
p = get_priv (self);
if (p->bus == bus)
return;
skel = G_DBUS_INTERFACE_SKELETON(p->skeleton);
if (p->bus != NULL)
{
if (skel != NULL)
g_dbus_interface_skeleton_unexport (skel);
g_clear_object (&p->bus);
}
if (bus != NULL)
{
GError * error;
p->bus = g_object_ref (bus);
error = NULL;
if (!g_dbus_interface_skeleton_export(skel,
bus,
BUS_PATH"/Testing",
&error))
{
g_warning ("Unable to export Testing properties: %s", error->message);
g_error_free (error);
}
}
}
/***
****
***/
static void
on_mock_battery_enabled_changed(DbusTesting * skeleton G_GNUC_UNUSED,
GParamSpec * pspec G_GNUC_UNUSED,
IndicatorPowerTesting * self)
{
update_device_provider (self);
}
static void
on_mock_battery_level_changed(DbusTesting * skeleton,
GParamSpec * pspec G_GNUC_UNUSED,
IndicatorPowerTesting * self)
{
g_object_set(get_priv(self)->battery_mock,
INDICATOR_POWER_DEVICE_PERCENTAGE, (gdouble)dbus_testing_get_mock_battery_level(skeleton),
NULL);
}
static void
on_mock_battery_state_changed(DbusTesting * skeleton,
GParamSpec * pspec G_GNUC_UNUSED,
IndicatorPowerTesting * self)
{
const gchar* state_str = dbus_testing_get_mock_battery_state(skeleton);
UpDeviceState state;
if (!g_strcmp0(state_str, "charging"))
{
state = UP_DEVICE_STATE_CHARGING;
}
else if (!g_strcmp0(state_str, "discharging"))
{
state = UP_DEVICE_STATE_DISCHARGING;
}
else
{
g_warning("%s unsupported state: '%s'", G_STRLOC, state_str);
state = UP_DEVICE_STATE_UNKNOWN;
}
g_object_set(get_priv(self)->battery_mock,
INDICATOR_POWER_DEVICE_STATE, (gint)state,
NULL);
}
static void
on_mock_battery_minutes_left_changed(DbusTesting * skeleton,
GParamSpec * pspec G_GNUC_UNUSED,
IndicatorPowerTesting * self)
{
g_object_set(get_priv(self)->battery_mock,
INDICATOR_POWER_DEVICE_TIME, (guint64)dbus_testing_get_mock_battery_minutes_left(skeleton),
NULL);
}
static void
on_bus_changed(IndicatorPowerService * service,
GParamSpec * spec G_GNUC_UNUSED,
IndicatorPowerTesting * self)
{
GObject * bus = NULL;
g_object_get(service, "bus", &bus, NULL);
set_bus(self, G_DBUS_CONNECTION(bus));
g_clear_object(&bus);
}
/***
**** GObject virtual functions
***/
static void
my_get_property(GObject * o,
guint property_id,
GValue * value,
GParamSpec * pspec)
{
IndicatorPowerTesting * const self = INDICATOR_POWER_TESTING (o);
priv_t * const p = get_priv(self);
switch (property_id)
{
case PROP_SERVICE:
g_value_set_object(value, p->service);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(o, property_id, pspec);
}
}
static void
my_set_property(GObject * o,
guint property_id,
const GValue * value,
GParamSpec * pspec)
{
IndicatorPowerTesting * const self = INDICATOR_POWER_TESTING (o);
priv_t * const p = get_priv(self);
switch (property_id)
{
case PROP_SERVICE:
g_assert(p->service == NULL); /* G_PARAM_CONSTRUCT_ONLY */
p->service = g_value_dup_object(value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(o, property_id, pspec);
}
}
static void
my_dispose(GObject * o)
{
IndicatorPowerTesting * const self = INDICATOR_POWER_TESTING(o);
priv_t * const p = get_priv (self);
set_bus(self, NULL);
g_clear_object(&p->skeleton);
g_clear_object(&p->provider_upower);
g_clear_object(&p->provider_mock);
g_clear_object(&p->battery_mock);
g_clear_object(&p->service);
G_OBJECT_CLASS (indicator_power_testing_parent_class)->dispose(o);
}
static void
my_finalize (GObject * o G_GNUC_UNUSED)
{
}
static void
my_constructed (GObject * o)
{
IndicatorPowerTesting * const self = INDICATOR_POWER_TESTING(o);
priv_t * const p = get_priv (self);
g_assert(p->service != NULL); /* G_PARAM_CONSTRUCT_ONLY */
g_signal_connect(p->service, "notify::bus", G_CALLBACK(on_bus_changed), o);
on_bus_changed(p->service, NULL, self);
update_device_provider(self);
}
/***
**** Instantiation
***/
static void
indicator_power_testing_init (IndicatorPowerTesting * self)
{
priv_t * const p = get_priv (self);
/* DBus Skeleton */
p->skeleton = dbus_testing_skeleton_new();
dbus_testing_set_mock_battery_level(p->skeleton, 50u);
dbus_testing_set_mock_battery_state(p->skeleton, "discharging");
dbus_testing_set_mock_battery_enabled(p->skeleton, FALSE);
dbus_testing_set_mock_battery_minutes_left(p->skeleton, 30);
g_signal_connect(p->skeleton, "notify::mock-battery-enabled",
G_CALLBACK(on_mock_battery_enabled_changed), self);
g_signal_connect(p->skeleton, "notify::mock-battery-level",
G_CALLBACK(on_mock_battery_level_changed), self);
g_signal_connect(p->skeleton, "notify::mock-battery-state",
G_CALLBACK(on_mock_battery_state_changed), self);
g_signal_connect(p->skeleton, "notify::mock-battery-minutes-left",
G_CALLBACK(on_mock_battery_minutes_left_changed), self);
/* Mock Battery */
p->battery_mock = indicator_power_device_new("/some/path",
UP_DEVICE_KIND_BATTERY,
"Some Model",
50.0,
UP_DEVICE_STATE_DISCHARGING,
60*30,
TRUE);
/* Mock Provider */
p->provider_mock = indicator_power_device_provider_mock_new();
indicator_power_device_provider_add_device(INDICATOR_POWER_DEVICE_PROVIDER_MOCK(p->provider_mock),
p->battery_mock);
/* UPower Provider */
p->provider_upower = indicator_power_device_provider_upower_new();
}
static void
indicator_power_testing_class_init (IndicatorPowerTestingClass * klass)
{
GObjectClass * object_class = G_OBJECT_CLASS (klass);
object_class->dispose = my_dispose;
object_class->finalize = my_finalize;
object_class->constructed = my_constructed;
object_class->get_property = my_get_property;
object_class->set_property = my_set_property;
properties[PROP_SERVICE] = g_param_spec_object (
"service",
"Servie",
"The Ayatana Indicator Power Service",
G_TYPE_OBJECT,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY);
g_object_class_install_properties (object_class, LAST_PROP, properties);
}
/***
**** Public API
***/
IndicatorPowerTesting *
indicator_power_testing_new (IndicatorPowerService * service)
{
GObject * o = g_object_new (INDICATOR_TYPE_POWER_TESTING, "service", service, NULL);
return INDICATOR_POWER_TESTING (o);
}