libnm-glib: add "pseudoproperties" for things like Client.GetDevices

Add generic handling for "properties" that consist of a "Get" method,
an "Added" signal, and a "Removed" signal, reusing some of the code
for handling object-array-valued properties. And load the values of
pseudo properties from _nm_object_reload/ensure_properties as well.
This commit is contained in:
Dan Winship 2012-01-10 12:38:19 -05:00 committed by Dan Williams
parent cc90f1010e
commit ad5daa098c
5 changed files with 247 additions and 236 deletions

View file

@ -106,8 +106,8 @@ static void proxy_name_owner_changed (DBusGProxy *proxy,
const char *new_owner,
gpointer user_data);
static void client_device_added_proxy (DBusGProxy *proxy, char *path, gpointer user_data);
static void client_device_removed_proxy (DBusGProxy *proxy, char *path, gpointer user_data);
static void client_device_added (NMObject *client, NMObject *device);
static void client_device_removed (NMObject *client, NMObject *device);
static void
nm_client_init (NMClient *client)
@ -256,6 +256,14 @@ register_properties (NMClient *client)
_nm_object_register_properties (NM_OBJECT (client),
priv->client_proxy,
property_info);
_nm_object_register_pseudo_property (NM_OBJECT (client),
priv->client_proxy,
"Devices",
&priv->devices,
NM_TYPE_DEVICE,
client_device_added,
client_device_removed);
}
#define NM_AUTH_PERMISSION_ENABLE_DISABLE_NETWORK "org.freedesktop.NetworkManager.enable-disable-network"
@ -421,34 +429,10 @@ client_recheck_permissions (DBusGProxy *proxy, gpointer user_data)
const GPtrArray *
nm_client_get_devices (NMClient *client)
{
NMClientPrivate *priv;
DBusGConnection *connection;
GValue value = { 0, };
GError *error = NULL;
GPtrArray *temp;
g_return_val_if_fail (NM_IS_CLIENT (client), NULL);
priv = NM_CLIENT_GET_PRIVATE (client);
if (priv->devices)
return handle_ptr_array_return (priv->devices);
if (!dbus_g_proxy_call (priv->client_proxy, "GetDevices", &error,
G_TYPE_INVALID,
DBUS_TYPE_G_ARRAY_OF_OBJECT_PATH, &temp,
G_TYPE_INVALID)) {
g_warning ("%s: error getting devices: %s\n", __func__, error->message);
g_error_free (error);
return NULL;
}
g_value_init (&value, DBUS_TYPE_G_ARRAY_OF_OBJECT_PATH);
g_value_take_boxed (&value, temp);
connection = nm_object_get_connection (NM_OBJECT (client));
_nm_object_array_demarshal (&value, &priv->devices, connection, nm_device_new);
g_value_unset (&value);
return handle_ptr_array_return (priv->devices);
_nm_object_ensure_inited (NM_OBJECT (client));
return handle_ptr_array_return (NM_CLIENT_GET_PRIVATE (client)->devices);
}
/**
@ -1182,43 +1166,15 @@ proxy_name_owner_changed (DBusGProxy *proxy,
}
static void
client_device_added_proxy (DBusGProxy *proxy, char *path, gpointer user_data)
client_device_added (NMObject *client, NMObject *device)
{
NMClient *client = NM_CLIENT (user_data);
NMClientPrivate *priv = NM_CLIENT_GET_PRIVATE (client);
GObject *device;
device = G_OBJECT (nm_client_get_device_by_path (client, path));
if (!device) {
DBusGConnection *connection = nm_object_get_connection (NM_OBJECT (client));
device = G_OBJECT (_nm_object_cache_get (path));
if (device) {
g_ptr_array_add (priv->devices, device);
} else {
device = G_OBJECT (nm_device_new (connection, path));
if (device)
g_ptr_array_add (priv->devices, device);
}
}
if (device)
g_signal_emit (client, signals[DEVICE_ADDED], 0, device);
g_signal_emit (client, signals[DEVICE_ADDED], 0, device);
}
static void
client_device_removed_proxy (DBusGProxy *proxy, char *path, gpointer user_data)
client_device_removed (NMObject *client, NMObject *device)
{
NMClient *client = NM_CLIENT (user_data);
NMClientPrivate *priv = NM_CLIENT_GET_PRIVATE (client);
NMDevice *device;
device = nm_client_get_device_by_path (client, path);
if (device) {
g_signal_emit (client, signals[DEVICE_REMOVED], 0, device);
g_ptr_array_remove (priv->devices, device);
g_object_unref (device);
}
g_signal_emit (client, signals[DEVICE_REMOVED], 0, device);
}
/****************************************************************/
@ -1279,20 +1235,6 @@ constructor (GType type,
register_properties (NM_CLIENT (object));
dbus_g_proxy_add_signal (priv->client_proxy, "DeviceAdded", DBUS_TYPE_G_OBJECT_PATH, G_TYPE_INVALID);
dbus_g_proxy_connect_signal (priv->client_proxy,
"DeviceAdded",
G_CALLBACK (client_device_added_proxy),
object,
NULL);
dbus_g_proxy_add_signal (priv->client_proxy, "DeviceRemoved", DBUS_TYPE_G_OBJECT_PATH, G_TYPE_INVALID);
dbus_g_proxy_connect_signal (priv->client_proxy,
"DeviceRemoved",
G_CALLBACK (client_device_removed_proxy),
object,
NULL);
/* Permissions */
dbus_g_proxy_add_signal (priv->client_proxy, "CheckPermissions", G_TYPE_INVALID);
dbus_g_proxy_connect_signal (priv->client_proxy,

View file

@ -255,34 +255,10 @@ nm_device_wifi_get_active_access_point (NMDeviceWifi *device)
const GPtrArray *
nm_device_wifi_get_access_points (NMDeviceWifi *device)
{
NMDeviceWifiPrivate *priv;
DBusGConnection *connection;
GValue value = { 0, };
GError *error = NULL;
GPtrArray *temp;
g_return_val_if_fail (NM_IS_DEVICE_WIFI (device), NULL);
priv = NM_DEVICE_WIFI_GET_PRIVATE (device);
if (priv->aps)
return handle_ptr_array_return (priv->aps);
if (!dbus_g_proxy_call (priv->proxy, "GetAccessPoints", &error,
G_TYPE_INVALID,
DBUS_TYPE_G_ARRAY_OF_OBJECT_PATH, &temp,
G_TYPE_INVALID)) {
g_warning ("%s: error getting access points: %s", __func__, error->message);
g_error_free (error);
return NULL;
}
g_value_init (&value, DBUS_TYPE_G_ARRAY_OF_OBJECT_PATH);
g_value_take_boxed (&value, temp);
connection = nm_object_get_connection (NM_OBJECT (device));
_nm_object_array_demarshal (&value, &priv->aps, connection, nm_access_point_new);
g_value_unset (&value);
return handle_ptr_array_return (priv->aps);
_nm_object_ensure_inited (NM_OBJECT (device));
return handle_ptr_array_return (NM_DEVICE_WIFI_GET_PRIVATE (device)->aps);
}
/**
@ -321,57 +297,28 @@ nm_device_wifi_get_access_point_by_path (NMDeviceWifi *device,
}
static void
access_point_added_proxy (DBusGProxy *proxy, char *path, gpointer user_data)
access_point_added (NMObject *self, NMObject *ap)
{
NMDeviceWifi *self = NM_DEVICE_WIFI (user_data);
NMDeviceWifiPrivate *priv;
GObject *ap;
g_return_if_fail (self != NULL);
ap = G_OBJECT (nm_device_wifi_get_access_point_by_path (self, path));
if (!ap) {
DBusGConnection *connection = nm_object_get_connection (NM_OBJECT (self));
priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
ap = G_OBJECT (_nm_object_cache_get (path));
if (ap) {
g_ptr_array_add (priv->aps, ap);
} else {
ap = G_OBJECT (nm_access_point_new (connection, path));
if (ap)
g_ptr_array_add (priv->aps, ap);
}
}
if (ap)
g_signal_emit (self, signals[ACCESS_POINT_ADDED], 0, NM_ACCESS_POINT (ap));
g_signal_emit (self, signals[ACCESS_POINT_ADDED], 0, ap);
}
static void
access_point_removed_proxy (DBusGProxy *proxy, char *path, gpointer user_data)
access_point_removed (NMObject *self_obj, NMObject *ap_obj)
{
NMDeviceWifi *self = NM_DEVICE_WIFI (user_data);
NMDeviceWifi *self = NM_DEVICE_WIFI (self_obj);
NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
NMAccessPoint *ap;
NMAccessPoint *ap = NM_ACCESS_POINT (ap_obj);
g_return_if_fail (self != NULL);
if (ap == priv->active_ap) {
g_object_unref (priv->active_ap);
priv->active_ap = NULL;
_nm_object_queue_notify (NM_OBJECT (self), NM_DEVICE_WIFI_ACTIVE_ACCESS_POINT);
ap = nm_device_wifi_get_access_point_by_path (self, path);
if (ap) {
if (ap == priv->active_ap) {
g_object_unref (priv->active_ap);
priv->active_ap = NULL;
_nm_object_queue_notify (NM_OBJECT (self), NM_DEVICE_WIFI_ACTIVE_ACCESS_POINT);
priv->rate = 0;
_nm_object_queue_notify (NM_OBJECT (self), NM_DEVICE_WIFI_BITRATE);
}
g_signal_emit (self, signals[ACCESS_POINT_REMOVED], 0, ap);
g_ptr_array_remove (priv->aps, ap);
g_object_unref (G_OBJECT (ap));
priv->rate = 0;
_nm_object_queue_notify (NM_OBJECT (self), NM_DEVICE_WIFI_BITRATE);
}
g_signal_emit (self, signals[ACCESS_POINT_REMOVED], 0, ap);
}
static void
@ -581,6 +528,14 @@ register_properties (NMDeviceWifi *device)
_nm_object_register_properties (NM_OBJECT (device),
priv->proxy,
property_info);
_nm_object_register_pseudo_property (NM_OBJECT (device),
priv->proxy,
"AccessPoints",
&priv->aps,
NM_TYPE_ACCESS_POINT,
access_point_added,
access_point_removed);
}
static GObject*
@ -604,20 +559,6 @@ constructor (GType type,
nm_object_get_path (NM_OBJECT (object)),
NM_DBUS_INTERFACE_DEVICE_WIRELESS);
dbus_g_proxy_add_signal (priv->proxy, "AccessPointAdded",
DBUS_TYPE_G_OBJECT_PATH,
G_TYPE_INVALID);
dbus_g_proxy_connect_signal (priv->proxy, "AccessPointAdded",
G_CALLBACK (access_point_added_proxy),
object, NULL);
dbus_g_proxy_add_signal (priv->proxy, "AccessPointRemoved",
DBUS_TYPE_G_OBJECT_PATH,
G_TYPE_INVALID);
dbus_g_proxy_connect_signal (priv->proxy, "AccessPointRemoved",
G_CALLBACK (access_point_removed_proxy),
object, NULL);
register_properties (NM_DEVICE_WIFI (object));
g_signal_connect (NM_DEVICE (object),

View file

@ -172,34 +172,10 @@ nm_device_wimax_get_active_nsp (NMDeviceWimax *wimax)
const GPtrArray *
nm_device_wimax_get_nsps (NMDeviceWimax *wimax)
{
NMDeviceWimaxPrivate *priv;
DBusGConnection *connection;
GValue value = { 0, };
GError *error = NULL;
GPtrArray *temp;
g_return_val_if_fail (NM_IS_DEVICE_WIMAX (wimax), NULL);
priv = NM_DEVICE_WIMAX_GET_PRIVATE (wimax);
if (priv->nsps)
return handle_ptr_array_return (priv->nsps);
if (!dbus_g_proxy_call (priv->proxy, "GetNspList", &error,
G_TYPE_INVALID,
DBUS_TYPE_G_ARRAY_OF_OBJECT_PATH, &temp,
G_TYPE_INVALID)) {
g_warning ("%s: error getting NSPs: %s", __func__, error->message);
g_error_free (error);
return NULL;
}
g_value_init (&value, DBUS_TYPE_G_ARRAY_OF_OBJECT_PATH);
g_value_take_boxed (&value, temp);
connection = nm_object_get_connection (NM_OBJECT (wimax));
_nm_object_array_demarshal (&value, &priv->nsps, connection, nm_wimax_nsp_new);
g_value_unset (&value);
return handle_ptr_array_return (priv->nsps);
_nm_object_ensure_inited (NM_OBJECT (wimax));
return handle_ptr_array_return (NM_DEVICE_WIMAX_GET_PRIVATE (wimax)->nsps);
}
/**
@ -238,54 +214,25 @@ nm_device_wimax_get_nsp_by_path (NMDeviceWimax *wimax,
}
static void
nsp_added_proxy (DBusGProxy *proxy, char *path, gpointer user_data)
nsp_added (NMObject *self, NMObject *nsp)
{
NMDeviceWimax *self = NM_DEVICE_WIMAX (user_data);
NMDeviceWimaxPrivate *priv;
GObject *nsp;
g_return_if_fail (self != NULL);
nsp = G_OBJECT (nm_device_wimax_get_nsp_by_path (self, path));
if (!nsp) {
DBusGConnection *connection = nm_object_get_connection (NM_OBJECT (self));
priv = NM_DEVICE_WIMAX_GET_PRIVATE (self);
nsp = G_OBJECT (_nm_object_cache_get (path));
if (nsp) {
g_ptr_array_add (priv->nsps, nsp);
} else {
nsp = G_OBJECT (nm_wimax_nsp_new (connection, path));
if (nsp)
g_ptr_array_add (priv->nsps, nsp);
}
}
if (nsp)
g_signal_emit (self, signals[NSP_ADDED], 0, nsp);
g_signal_emit (self, signals[NSP_ADDED], 0, nsp);
}
static void
nsp_removed_proxy (DBusGProxy *proxy, char *path, gpointer user_data)
nsp_removed (NMObject *self_obj, NMObject *nsp_obj)
{
NMDeviceWimax *self = NM_DEVICE_WIMAX (user_data);
NMDeviceWimax *self = NM_DEVICE_WIMAX (self_obj);
NMDeviceWimaxPrivate *priv = NM_DEVICE_WIMAX_GET_PRIVATE (self);
NMWimaxNsp *nsp;
NMWimaxNsp *nsp = NM_WIMAX_NSP (nsp_obj);
g_return_if_fail (self != NULL);
nsp = nm_device_wimax_get_nsp_by_path (self, path);
if (nsp) {
if (nsp == priv->active_nsp) {
g_object_unref (priv->active_nsp);
priv->active_nsp = NULL;
_nm_object_queue_notify (NM_OBJECT (self), NM_DEVICE_WIMAX_ACTIVE_NSP);
}
g_signal_emit (self, signals[NSP_REMOVED], 0, nsp);
g_ptr_array_remove (priv->nsps, nsp);
g_object_unref (G_OBJECT (nsp));
if (nsp == priv->active_nsp) {
g_object_unref (priv->active_nsp);
priv->active_nsp = NULL;
_nm_object_queue_notify (NM_OBJECT (self), NM_DEVICE_WIMAX_ACTIVE_NSP);
}
g_signal_emit (self, signals[NSP_REMOVED], 0, nsp);
}
static void
@ -568,6 +515,14 @@ register_properties (NMDeviceWimax *wimax)
_nm_object_register_properties (NM_OBJECT (wimax),
priv->proxy,
property_info);
_nm_object_register_pseudo_property (NM_OBJECT (wimax),
priv->proxy,
"NspList",
&priv->nsps,
NM_TYPE_WIMAX_NSP,
nsp_added,
nsp_removed);
}
static GObject*
@ -591,20 +546,6 @@ constructor (GType type,
nm_object_get_path (NM_OBJECT (object)),
NM_DBUS_INTERFACE_DEVICE_WIMAX);
dbus_g_proxy_add_signal (priv->proxy, "NspAdded",
DBUS_TYPE_G_OBJECT_PATH,
G_TYPE_INVALID);
dbus_g_proxy_connect_signal (priv->proxy, "NspAdded",
G_CALLBACK (nsp_added_proxy),
object, NULL);
dbus_g_proxy_add_signal (priv->proxy, "NspRemoved",
DBUS_TYPE_G_OBJECT_PATH,
G_TYPE_INVALID);
dbus_g_proxy_connect_signal (priv->proxy, "NspRemoved",
G_CALLBACK (nsp_removed_proxy),
object, NULL);
register_properties (NM_DEVICE_WIMAX (object));
g_signal_connect (object,

View file

@ -49,6 +49,17 @@ gboolean _nm_object_reload_properties (NMObject *object, GError **error);
void _nm_object_process_properties_changed (NMObject *self, GHashTable *properties);
typedef void (*NMPseudoPropertyChangedFunc) (NMObject *self, NMObject *changed);
void _nm_object_register_pseudo_property (NMObject *object,
DBusGProxy *proxy,
const char *name,
gpointer field,
GType object_type,
NMPseudoPropertyChangedFunc added_func,
NMPseudoPropertyChangedFunc removed_func);
void _nm_object_reload_pseudo_property (NMObject *object,
const char *name);
void _nm_object_queue_notify (NMObject *object, const char *property);
/* DBus property accessors */

View file

@ -47,12 +47,24 @@ typedef struct {
gpointer field;
} PropertyInfo;
typedef struct {
PropertyInfo pi;
NMObject *self;
DBusGProxy *proxy;
char *get_method;
NMPseudoPropertyChangedFunc added_func;
NMPseudoPropertyChangedFunc removed_func;
} PseudoPropertyInfo;
typedef struct {
DBusGConnection *connection;
char *path;
DBusGProxy *properties_proxy;
GSList *property_interfaces;
GSList *property_tables;
GHashTable *pseudo_properties;
NMObject *parent;
GSList *notify_props;
@ -143,6 +155,9 @@ finalize (GObject *object)
g_slist_free (priv->property_tables);
g_free (priv->path);
if (priv->pseudo_properties)
g_hash_table_destroy (priv->pseudo_properties);
G_OBJECT_CLASS (nm_object_parent_class)->finalize (object);
}
@ -752,6 +767,8 @@ _nm_object_reload_properties (NMObject *object, GError **error)
NMObjectPrivate *priv = NM_OBJECT_GET_PRIVATE (object);
GHashTable *props = NULL;
GSList *p;
GHashTableIter pp;
gpointer name, info;
if (!priv->property_interfaces)
return TRUE;
@ -770,6 +787,12 @@ _nm_object_reload_properties (NMObject *object, GError **error)
g_hash_table_destroy (props);
}
if (priv->pseudo_properties) {
g_hash_table_iter_init (&pp, priv->pseudo_properties);
while (g_hash_table_iter_next (&pp, &name, &info))
_nm_object_reload_pseudo_property (object, name);
}
return TRUE;
}
@ -850,3 +873,156 @@ _nm_object_set_property (NMObject *object,
*/
}
}
static void
pseudo_property_object_created (GObject *obj, gpointer user_data)
{
PseudoPropertyInfo *ppi = user_data;
if (obj) {
GPtrArray **list_p = (GPtrArray **)ppi->pi.field;
if (!*list_p)
*list_p = g_ptr_array_new ();
g_ptr_array_add (*list_p, obj);
ppi->added_func (ppi->self, NM_OBJECT (obj));
}
}
static void
pseudo_property_added (DBusGProxy *proxy, const char *path, gpointer user_data)
{
PseudoPropertyInfo *ppi = user_data;
NMObjectPrivate *priv = NM_OBJECT_GET_PRIVATE (ppi->self);
NMObject *obj;
obj = _nm_object_cache_get (path);
if (obj)
pseudo_property_object_created (G_OBJECT (obj), ppi);
else {
_nm_object_create_async (ppi->pi.object_type, priv->connection, path,
pseudo_property_object_created, ppi);
}
}
static void
pseudo_property_removed (DBusGProxy *proxy, const char *path, gpointer user_data)
{
PseudoPropertyInfo *ppi = user_data;
GPtrArray *list = *(GPtrArray **)ppi->pi.field;
NMObject *obj = NULL;
int i;
if (!list)
return;
for (i = 0; i < list->len; i++) {
obj = list->pdata[i];
if (!strcmp (path, nm_object_get_path (obj))) {
g_ptr_array_remove_index (list, i);
ppi->removed_func (ppi->self, obj);
g_object_unref (obj);
return;
}
}
}
static void
free_pseudo_property (PseudoPropertyInfo *ppi)
{
g_object_unref (ppi->proxy);
g_free (ppi->get_method);
g_slice_free (PseudoPropertyInfo, ppi);
}
void
_nm_object_register_pseudo_property (NMObject *object,
DBusGProxy *proxy,
const char *name,
gpointer field,
GType object_type,
NMPseudoPropertyChangedFunc added_func,
NMPseudoPropertyChangedFunc removed_func)
{
NMObjectPrivate *priv = NM_OBJECT_GET_PRIVATE (object);
PseudoPropertyInfo *ppi;
int basename_len;
char *added_signal, *removed_signal;
g_return_if_fail (NM_IS_OBJECT (object));
g_return_if_fail (proxy != NULL);
ppi = g_slice_new0 (PseudoPropertyInfo);
ppi->pi.field = field;
ppi->pi.object_type = object_type;
ppi->self = object;
ppi->proxy = g_object_ref (proxy);
ppi->added_func = added_func;
ppi->removed_func = removed_func;
basename_len = strlen (name);
if (basename_len > 4 && !strcmp (name + basename_len - 4, "List"))
basename_len -= 4;
else if (basename_len > 1 && name[basename_len - 1] == 's')
basename_len--;
else
g_assert_not_reached ();
ppi->get_method = g_strdup_printf ("Get%s", name);
added_signal = g_strdup_printf ("%.*sAdded", basename_len, name);
removed_signal = g_strdup_printf ("%.*sRemoved", basename_len, name);
if (!priv->pseudo_properties) {
priv->pseudo_properties = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, (GDestroyNotify) free_pseudo_property);
}
g_hash_table_insert (priv->pseudo_properties, g_strdup (name), ppi);
dbus_g_proxy_add_signal (proxy, added_signal,
DBUS_TYPE_G_OBJECT_PATH,
G_TYPE_INVALID);
dbus_g_proxy_connect_signal (proxy, added_signal,
G_CALLBACK (pseudo_property_added),
ppi, NULL);
dbus_g_proxy_add_signal (proxy, removed_signal,
DBUS_TYPE_G_OBJECT_PATH,
G_TYPE_INVALID);
dbus_g_proxy_connect_signal (proxy, removed_signal,
G_CALLBACK (pseudo_property_removed),
ppi, NULL);
g_free (added_signal);
g_free (removed_signal);
}
void
_nm_object_reload_pseudo_property (NMObject *object,
const char *name)
{
NMObjectPrivate *priv = NM_OBJECT_GET_PRIVATE (object);
PseudoPropertyInfo *ppi;
GPtrArray *temp;
GError *error = NULL;
GValue value = { 0, };
g_return_if_fail (NM_IS_OBJECT (object));
g_return_if_fail (name != NULL);
ppi = g_hash_table_lookup (priv->pseudo_properties, name);
g_return_if_fail (ppi != NULL);
if (!dbus_g_proxy_call (ppi->proxy, ppi->get_method, &error,
G_TYPE_INVALID,
DBUS_TYPE_G_ARRAY_OF_OBJECT_PATH, &temp,
G_TYPE_INVALID)) {
g_warning ("%s: error calling %s: %s", __func__, ppi->get_method, error->message);
g_error_free (error);
return;
}
g_value_init (&value, DBUS_TYPE_G_ARRAY_OF_OBJECT_PATH);
g_value_take_boxed (&value, temp);
handle_object_array_property (object, NULL, &value, &ppi->pi, TRUE);
g_value_unset (&value);
}