summaryrefslogtreecommitdiff
path: root/libnm-glib
diff options
context:
space:
mode:
authorDan Winship <danw@gnome.org>2012-01-11 07:56:04 -0500
committerDan Williams <dcbw@redhat.com>2012-02-03 10:33:43 -0600
commitcc90f1010eeaf6987fbe3e042bf96b01b52dd5de (patch)
tree8b67a8bb1294278f5ba43cd434eb310d74274b04 /libnm-glib
parent5afcee46936ab547a95fdaa7e415aa3ba6de47d2 (diff)
libnm-glib: simplify handling of object and object array properties
Add an "object_type" field to NMPropertiesInfo, and use that with DBUS_TYPE_G_OBJECT_PATH and DBUS_TYPE_G_ARRAY_OF_OBJECT_PATH properties so that we don't need custom marshallers for each one. When creating an NMDevice or NMActiveConnection, we need to fetch an extra property first to figure out the exact subclass to use, so add a bit of infrastructure for that as well. Also, do that preprocessing asynchronously when processing a property change notification, so that it doesn't block the main loop.
Diffstat (limited to 'libnm-glib')
-rw-r--r--libnm-glib/nm-active-connection.c131
-rw-r--r--libnm-glib/nm-client.c58
-rw-r--r--libnm-glib/nm-device-private.h4
-rw-r--r--libnm-glib/nm-device-wifi.c38
-rw-r--r--libnm-glib/nm-device-wimax.c38
-rw-r--r--libnm-glib/nm-device.c373
-rw-r--r--libnm-glib/nm-object-private.h10
-rw-r--r--libnm-glib/nm-object.c256
8 files changed, 517 insertions, 391 deletions
diff --git a/libnm-glib/nm-active-connection.c b/libnm-glib/nm-active-connection.c
index a68da56b67..0c922b7b40 100644
--- a/libnm-glib/nm-active-connection.c
+++ b/libnm-glib/nm-active-connection.c
@@ -28,14 +28,24 @@
#include "nm-object-private.h"
#include "nm-types-private.h"
#include "nm-device.h"
+#include "nm-device-private.h"
#include "nm-connection.h"
+#include "nm-vpn-connection.h"
-G_DEFINE_TYPE (NMActiveConnection, nm_active_connection, NM_TYPE_OBJECT)
+static GType nm_active_connection_type_for_path (DBusGConnection *connection,
+ const char *path);
+static void nm_active_connection_type_for_path_async (DBusGConnection *connection,
+ const char *path,
+ NMObjectTypeCallbackFunc callback,
+ gpointer user_data);
-#define NM_ACTIVE_CONNECTION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_ACTIVE_CONNECTION, NMActiveConnectionPrivate))
-
-static gboolean demarshal_devices (NMObject *object, GParamSpec *pspec, GValue *value, gpointer field);
+G_DEFINE_TYPE_WITH_CODE (NMActiveConnection, nm_active_connection, NM_TYPE_OBJECT,
+ _nm_object_register_type_func (g_define_type_id,
+ nm_active_connection_type_for_path,
+ nm_active_connection_type_for_path_async);
+ )
+#define NM_ACTIVE_CONNECTION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_ACTIVE_CONNECTION, NMActiveConnectionPrivate))
typedef struct {
gboolean disposed;
@@ -95,6 +105,104 @@ nm_active_connection_new (DBusGConnection *connection, const char *path)
NULL);
}
+static GType
+nm_active_connection_type_for_path (DBusGConnection *connection,
+ const char *path)
+{
+ DBusGProxy *proxy;
+ GError *error = NULL;
+ GValue value = {0,};
+ GType type;
+
+ proxy = dbus_g_proxy_new_for_name (connection,
+ NM_DBUS_SERVICE,
+ path,
+ "org.freedesktop.DBus.Properties");
+ if (!proxy) {
+ g_warning ("%s: couldn't create D-Bus object proxy.", __func__);
+ return G_TYPE_INVALID;
+ }
+
+ /* Have to create an NMVPNConnection if it's a VPN connection, otherwise
+ * a plain NMActiveConnection.
+ */
+ if (dbus_g_proxy_call (proxy,
+ "Get", &error,
+ G_TYPE_STRING, NM_DBUS_INTERFACE_ACTIVE_CONNECTION,
+ G_TYPE_STRING, "Vpn",
+ G_TYPE_INVALID,
+ G_TYPE_VALUE, &value, G_TYPE_INVALID)) {
+ if (g_value_get_boolean (&value))
+ type = NM_TYPE_VPN_CONNECTION;
+ else
+ type = NM_TYPE_ACTIVE_CONNECTION;
+ } else {
+ g_warning ("Error in getting active connection 'Vpn' property: (%d) %s",
+ error->code, error->message);
+ g_error_free (error);
+ type = G_TYPE_INVALID;
+ }
+
+ g_object_unref (proxy);
+ return type;
+}
+
+typedef struct {
+ DBusGConnection *connection;
+ NMObjectTypeCallbackFunc callback;
+ gpointer user_data;
+} NMActiveConnectionAsyncData;
+
+static void
+async_got_type (DBusGProxy *proxy, DBusGProxyCall *call, gpointer user_data)
+{
+ NMActiveConnectionAsyncData *async_data = user_data;
+ GValue value = G_VALUE_INIT;
+ const char *path = dbus_g_proxy_get_path (proxy);
+ GError *error = NULL;
+ GType type;
+
+ if (dbus_g_proxy_end_call (proxy, call, &error,
+ G_TYPE_VALUE, &value,
+ G_TYPE_INVALID)) {
+ if (g_value_get_boolean (&value))
+ type = NM_TYPE_VPN_CONNECTION;
+ else
+ type = NM_TYPE_ACTIVE_CONNECTION;
+ } else {
+ g_warning ("%s: could not read properties for %s: %s", __func__, path, error->message);
+ type = G_TYPE_INVALID;
+ }
+
+ async_data->callback (type, async_data->user_data);
+
+ g_object_unref (proxy);
+ g_slice_free (NMActiveConnectionAsyncData, async_data);
+}
+
+static void
+nm_active_connection_type_for_path_async (DBusGConnection *connection,
+ const char *path,
+ NMObjectTypeCallbackFunc callback,
+ gpointer user_data)
+{
+ NMActiveConnectionAsyncData *async_data;
+ DBusGProxy *proxy;
+
+ async_data = g_slice_new (NMActiveConnectionAsyncData);
+ async_data->connection = connection;
+ async_data->callback = callback;
+ async_data->user_data = user_data;
+
+ proxy = dbus_g_proxy_new_for_name (connection, NM_DBUS_SERVICE, path,
+ "org.freedesktop.DBus.Properties");
+ dbus_g_proxy_begin_call (proxy, "Get",
+ async_got_type, async_data, NULL,
+ G_TYPE_STRING, NM_DBUS_INTERFACE_ACTIVE_CONNECTION,
+ G_TYPE_STRING, "Vpn",
+ G_TYPE_INVALID);
+}
+
/**
* nm_active_connection_get_connection:
* @connection: a #NMActiveConnection
@@ -316,19 +424,6 @@ get_property (GObject *object,
}
}
-static gboolean
-demarshal_devices (NMObject *object, GParamSpec *pspec, GValue *value, gpointer field)
-{
- DBusGConnection *connection;
-
- connection = nm_object_get_connection (object);
- if (!_nm_object_array_demarshal (value, (GPtrArray **) field, connection, nm_device_new))
- return FALSE;
-
- _nm_object_queue_notify (object, NM_ACTIVE_CONNECTION_DEVICES);
- return TRUE;
-}
-
static void
register_properties (NMActiveConnection *connection)
{
@@ -337,7 +432,7 @@ register_properties (NMActiveConnection *connection)
{ NM_ACTIVE_CONNECTION_CONNECTION, &priv->connection },
{ NM_ACTIVE_CONNECTION_UUID, &priv->uuid },
{ NM_ACTIVE_CONNECTION_SPECIFIC_OBJECT, &priv->specific_object },
- { NM_ACTIVE_CONNECTION_DEVICES, &priv->devices, demarshal_devices },
+ { NM_ACTIVE_CONNECTION_DEVICES, &priv->devices, NULL, NM_TYPE_DEVICE },
{ NM_ACTIVE_CONNECTION_STATE, &priv->state },
{ NM_ACTIVE_CONNECTION_DEFAULT, &priv->is_default },
{ NM_ACTIVE_CONNECTION_DEFAULT6, &priv->is_default6 },
diff --git a/libnm-glib/nm-client.c b/libnm-glib/nm-client.c
index 9bf8bcb3e6..a0f6214f3c 100644
--- a/libnm-glib/nm-client.c
+++ b/libnm-glib/nm-client.c
@@ -235,62 +235,6 @@ update_wimax_status (NMClient *client, gboolean notify)
}
}
-static GObject *
-new_active_connection (DBusGConnection *connection, const char *path)
-{
- DBusGProxy *proxy;
- GError *error = NULL;
- GValue value = {0,};
- GObject *object = NULL;
-
- proxy = dbus_g_proxy_new_for_name (connection,
- NM_DBUS_SERVICE,
- path,
- "org.freedesktop.DBus.Properties");
- if (!proxy) {
- g_warning ("%s: couldn't create D-Bus object proxy.", __func__);
- return NULL;
- }
-
- /* Have to create an NMVPNConnection if it's a VPN connection, otherwise
- * a plain NMActiveConnection.
- */
- if (dbus_g_proxy_call (proxy,
- "Get", &error,
- G_TYPE_STRING, NM_DBUS_INTERFACE_ACTIVE_CONNECTION,
- G_TYPE_STRING, "Vpn",
- G_TYPE_INVALID,
- G_TYPE_VALUE, &value, G_TYPE_INVALID)) {
- if (g_value_get_boolean (&value))
- object = nm_vpn_connection_new (connection, path);
- else
- object = nm_active_connection_new (connection, path);
- } else {
- g_warning ("Error in getting active connection 'Vpn' property: (%d) %s",
- error->code, error->message);
- g_error_free (error);
- }
-
- g_object_unref (proxy);
- return object;
-}
-
-static gboolean
-demarshal_active_connections (NMObject *object,
- GParamSpec *pspec,
- GValue *value,
- gpointer field)
-{
- DBusGConnection *connection;
-
- connection = nm_object_get_connection (object);
- if (!_nm_object_array_demarshal (value, (GPtrArray **) field, connection, new_active_connection))
- return FALSE;
-
- _nm_object_queue_notify (object, NM_CLIENT_ACTIVE_CONNECTIONS);
- return TRUE;
-}
-
static void
register_properties (NMClient *client)
{
@@ -305,7 +249,7 @@ register_properties (NMClient *client)
{ NM_CLIENT_WWAN_HARDWARE_ENABLED, &priv->wwan_hw_enabled },
{ NM_CLIENT_WIMAX_ENABLED, &priv->wimax_enabled },
{ NM_CLIENT_WIMAX_HARDWARE_ENABLED, &priv->wimax_hw_enabled },
- { NM_CLIENT_ACTIVE_CONNECTIONS, &priv->active_connections, demarshal_active_connections },
+ { NM_CLIENT_ACTIVE_CONNECTIONS, &priv->active_connections, NULL, NM_TYPE_ACTIVE_CONNECTION },
{ NULL },
};
diff --git a/libnm-glib/nm-device-private.h b/libnm-glib/nm-device-private.h
index 2c56a0e646..5abf03f301 100644
--- a/libnm-glib/nm-device-private.h
+++ b/libnm-glib/nm-device-private.h
@@ -29,8 +29,4 @@ DBusGConnection *nm_device_get_connection (NMDevice *device);
const char *nm_device_get_path (NMDevice *device);
DBusGProxy *nm_device_get_properties_proxy (NMDevice *device);
-/* static methods */
-NMDeviceType nm_device_type_for_path (DBusGConnection *connection,
- const char *path);
-
#endif /* NM_DEVICE_PRIVATE_H */
diff --git a/libnm-glib/nm-device-wifi.c b/libnm-glib/nm-device-wifi.c
index 91106d3eeb..ca0dfba0e0 100644
--- a/libnm-glib/nm-device-wifi.c
+++ b/libnm-glib/nm-device-wifi.c
@@ -40,8 +40,6 @@ G_DEFINE_TYPE (NMDeviceWifi, nm_device_wifi, NM_TYPE_DEVICE)
#define NM_DEVICE_WIFI_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DEVICE_WIFI, NMDeviceWifiPrivate))
-static gboolean demarshal_active_ap (NMObject *object, GParamSpec *pspec, GValue *value, gpointer field);
-
void _nm_device_wifi_set_wireless_enabled (NMDeviceWifi *device, gboolean enabled);
typedef struct {
@@ -566,40 +564,6 @@ state_changed_cb (NMDevice *device, GParamSpec *pspec, gpointer user_data)
}
}
-static gboolean
-demarshal_active_ap (NMObject *object, GParamSpec *pspec, GValue *value, gpointer field)
-{
- NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (object);
- const char *path;
- NMAccessPoint *ap = NULL;
- DBusGConnection *connection;
-
- if (value) {
- if (!G_VALUE_HOLDS (value, DBUS_TYPE_G_OBJECT_PATH))
- return FALSE;
-
- path = g_value_get_boxed (value);
- if (path) {
- ap = NM_ACCESS_POINT (_nm_object_cache_get (path));
- if (!ap) {
- connection = nm_object_get_connection (object);
- ap = NM_ACCESS_POINT (nm_access_point_new (connection, path));
- }
- }
- }
-
- if (priv->active_ap) {
- g_object_unref (priv->active_ap);
- priv->active_ap = NULL;
- }
-
- if (ap)
- priv->active_ap = ap;
-
- _nm_object_queue_notify (object, NM_DEVICE_WIFI_ACTIVE_ACCESS_POINT);
- return TRUE;
-}
-
static void
register_properties (NMDeviceWifi *device)
{
@@ -609,7 +573,7 @@ register_properties (NMDeviceWifi *device)
{ NM_DEVICE_WIFI_PERMANENT_HW_ADDRESS, &priv->perm_hw_address },
{ NM_DEVICE_WIFI_MODE, &priv->mode },
{ NM_DEVICE_WIFI_BITRATE, &priv->rate },
- { NM_DEVICE_WIFI_ACTIVE_ACCESS_POINT, &priv->active_ap, demarshal_active_ap },
+ { NM_DEVICE_WIFI_ACTIVE_ACCESS_POINT, &priv->active_ap, NULL, NM_TYPE_ACCESS_POINT },
{ NM_DEVICE_WIFI_CAPABILITIES, &priv->wireless_caps },
{ NULL },
};
diff --git a/libnm-glib/nm-device-wimax.c b/libnm-glib/nm-device-wimax.c
index d9555a3297..e464dd99f8 100644
--- a/libnm-glib/nm-device-wimax.c
+++ b/libnm-glib/nm-device-wimax.c
@@ -38,8 +38,6 @@ G_DEFINE_TYPE (NMDeviceWimax, nm_device_wimax, NM_TYPE_DEVICE)
#define NM_DEVICE_WIMAX_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DEVICE_WIMAX, NMDeviceWimaxPrivate))
-static gboolean demarshal_active_nsp (NMObject *object, GParamSpec *pspec, GValue *value, gpointer field);
-
void _nm_device_wimax_set_wireless_enabled (NMDeviceWimax *wimax, gboolean enabled);
typedef struct {
@@ -552,47 +550,13 @@ state_changed_cb (NMDevice *device, GParamSpec *pspec, gpointer user_data)
}
}
-static gboolean
-demarshal_active_nsp (NMObject *object, GParamSpec *pspec, GValue *value, gpointer field)
-{
- NMDeviceWimaxPrivate *priv = NM_DEVICE_WIMAX_GET_PRIVATE (object);
- const char *path;
- NMWimaxNsp *nsp = NULL;
- DBusGConnection *connection;
-
- if (value) {
- if (!G_VALUE_HOLDS (value, DBUS_TYPE_G_OBJECT_PATH))
- return FALSE;
-
- path = g_value_get_boxed (value);
- if (path) {
- nsp = NM_WIMAX_NSP (_nm_object_cache_get (path));
- if (!nsp) {
- connection = nm_object_get_connection (object);
- nsp = NM_WIMAX_NSP (nm_wimax_nsp_new (connection, path));
- }
- }
- }
-
- if (priv->active_nsp) {
- g_object_unref (priv->active_nsp);
- priv->active_nsp = NULL;
- }
-
- if (nsp)
- priv->active_nsp = nsp;
-
- _nm_object_queue_notify (object, NM_DEVICE_WIMAX_ACTIVE_NSP);
- return TRUE;
-}
-
static void
register_properties (NMDeviceWimax *wimax)
{
NMDeviceWimaxPrivate *priv = NM_DEVICE_WIMAX_GET_PRIVATE (wimax);
const NMPropertiesInfo property_info[] = {
{ NM_DEVICE_WIMAX_HW_ADDRESS, &priv->hw_address },
- { NM_DEVICE_WIMAX_ACTIVE_NSP, &priv->active_nsp, demarshal_active_nsp },
+ { NM_DEVICE_WIMAX_ACTIVE_NSP, &priv->active_nsp, NULL, NM_TYPE_WIMAX_NSP },
{ NM_DEVICE_WIMAX_CENTER_FREQUENCY, &priv->center_freq },
{ NM_DEVICE_WIMAX_RSSI, &priv->rssi },
{ NM_DEVICE_WIMAX_CINR, &priv->cinr },
diff --git a/libnm-glib/nm-device.c b/libnm-glib/nm-device.c
index 208f415074..616f110c10 100644
--- a/libnm-glib/nm-device.c
+++ b/libnm-glib/nm-device.c
@@ -39,7 +39,17 @@
#include "nm-marshal.h"
#include "nm-dbus-glib-types.h"
-G_DEFINE_TYPE (NMDevice, nm_device, NM_TYPE_OBJECT)
+static GType nm_device_type_for_path (DBusGConnection *connection,
+ const char *path);
+static void nm_device_type_for_path_async (DBusGConnection *connection,
+ const char *path,
+ NMObjectTypeCallbackFunc callback,
+ gpointer user_data);
+
+G_DEFINE_TYPE_WITH_CODE (NMDevice, nm_device, NM_TYPE_OBJECT,
+ _nm_object_register_type_func (g_define_type_id, nm_device_type_for_path,
+ nm_device_type_for_path_async);
+ )
#define NM_DEVICE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DEVICE, NMDevicePrivate))
@@ -107,176 +117,6 @@ nm_device_init (NMDevice *device)
priv->state = NM_DEVICE_STATE_UNKNOWN;
}
-static gboolean
-demarshal_ip4_config (NMObject *object, GParamSpec *pspec, GValue *value, gpointer field)
-{
- NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (object);
- const char *path;
- NMIP4Config *config = NULL;
- DBusGConnection *connection;
-
- if (value) {
- if (!G_VALUE_HOLDS (value, DBUS_TYPE_G_OBJECT_PATH))
- return FALSE;
-
- path = g_value_get_boxed (value);
- if (path) {
- config = NM_IP4_CONFIG (_nm_object_cache_get (path));
- if (!config) {
- connection = nm_object_get_connection (object);
- config = NM_IP4_CONFIG (nm_ip4_config_new (connection, path));
- }
- }
- }
-
- if (priv->ip4_config) {
- g_object_unref (priv->ip4_config);
- priv->ip4_config = NULL;
- }
-
- if (config)
- priv->ip4_config = config;
-
- _nm_object_queue_notify (object, NM_DEVICE_IP4_CONFIG);
- return TRUE;
-}
-
-static gboolean
-demarshal_dhcp4_config (NMObject *object, GParamSpec *pspec, GValue *value, gpointer field)
-{
- NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (object);
- const char *path;
- NMDHCP4Config *config = NULL;
- DBusGConnection *connection;
-
- if (value) {
- if (!G_VALUE_HOLDS (value, DBUS_TYPE_G_OBJECT_PATH))
- return FALSE;
-
- path = g_value_get_boxed (value);
- if (path) {
- config = NM_DHCP4_CONFIG (_nm_object_cache_get (path));
- if (!config) {
- connection = nm_object_get_connection (object);
- config = NM_DHCP4_CONFIG (nm_dhcp4_config_new (connection, path));
- }
- }
- }
-
- if (priv->dhcp4_config) {
- g_object_unref (priv->dhcp4_config);
- priv->dhcp4_config = NULL;
- }
-
- if (config)
- priv->dhcp4_config = config;
-
- _nm_object_queue_notify (object, NM_DEVICE_DHCP4_CONFIG);
- return TRUE;
-}
-
-static gboolean
-demarshal_ip6_config (NMObject *object, GParamSpec *pspec, GValue *value, gpointer field)
-{
- NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (object);
- const char *path;
- NMIP6Config *config = NULL;
- DBusGConnection *connection;
-
- if (value) {
- if (!G_VALUE_HOLDS (value, DBUS_TYPE_G_OBJECT_PATH))
- return FALSE;
-
- path = g_value_get_boxed (value);
- if (path) {
- config = NM_IP6_CONFIG (_nm_object_cache_get (path));
- if (!config) {
- connection = nm_object_get_connection (object);
- config = NM_IP6_CONFIG (nm_ip6_config_new (connection, path));
- }
- }
- }
-
- if (priv->ip6_config) {
- g_object_unref (priv->ip6_config);
- priv->ip6_config = NULL;
- }
-
- if (config)
- priv->ip6_config = config;
-
- _nm_object_queue_notify (object, NM_DEVICE_IP6_CONFIG);
- return TRUE;
-}
-
-static gboolean
-demarshal_dhcp6_config (NMObject *object, GParamSpec *pspec, GValue *value, gpointer field)
-{
- NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (object);
- const char *path;
- NMDHCP6Config *config = NULL;
- DBusGConnection *connection;
-
- if (value) {
- if (!G_VALUE_HOLDS (value, DBUS_TYPE_G_OBJECT_PATH))
- return FALSE;
-
- path = g_value_get_boxed (value);
- if (path) {
- config = NM_DHCP6_CONFIG (_nm_object_cache_get (path));
- if (!config) {
- connection = nm_object_get_connection (object);
- config = NM_DHCP6_CONFIG (nm_dhcp6_config_new (connection, path));
- }
- }
- }
-
- if (priv->dhcp6_config) {
- g_object_unref (priv->dhcp6_config);
- priv->dhcp6_config = NULL;
- }
-
- if (config)
- priv->dhcp6_config = config;
-
- _nm_object_queue_notify (object, NM_DEVICE_DHCP6_CONFIG);
- return TRUE;
-}
-
-static gboolean
-demarshal_active_connection (NMObject *object, GParamSpec *pspec, GValue *value, gpointer field)
-{
- NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (object);
- const char *path;
- NMActiveConnection *active = NULL;
- DBusGConnection *connection;
-
- if (value) {
- if (!G_VALUE_HOLDS (value, DBUS_TYPE_G_OBJECT_PATH))
- return FALSE;
-
- path = g_value_get_boxed (value);
- if (path) {
- active = NM_ACTIVE_CONNECTION (_nm_object_cache_get (path));
- if (!active) {
- connection = nm_object_get_connection (object);
- active = NM_ACTIVE_CONNECTION (nm_active_connection_new (connection, path));
- }
- }
- }
-
- if (priv->active_connection) {
- g_object_unref (priv->active_connection);
- priv->active_connection = NULL;
- }
-
- if (active)
- priv->active_connection = active;
-
- _nm_object_queue_notify (object, NM_DEVICE_ACTIVE_CONNECTION);
- return TRUE;
-}
-
static void
register_properties (NMDevice *device)
{
@@ -289,12 +129,12 @@ register_properties (NMDevice *device)
{ NM_DEVICE_CAPABILITIES, &priv->capabilities },
{ NM_DEVICE_MANAGED, &priv->managed },
{ NM_DEVICE_FIRMWARE_MISSING, &priv->firmware_missing },
- { NM_DEVICE_IP4_CONFIG, &priv->ip4_config, demarshal_ip4_config },
- { NM_DEVICE_DHCP4_CONFIG, &priv->dhcp4_config, demarshal_dhcp4_config },
- { NM_DEVICE_IP6_CONFIG, &priv->ip6_config, demarshal_ip6_config },
- { NM_DEVICE_DHCP6_CONFIG, &priv->dhcp6_config, demarshal_dhcp6_config },
+ { NM_DEVICE_IP4_CONFIG, &priv->ip4_config, NULL, NM_TYPE_IP4_CONFIG },
+ { NM_DEVICE_DHCP4_CONFIG, &priv->dhcp4_config, NULL, NM_TYPE_DHCP4_CONFIG },
+ { NM_DEVICE_IP6_CONFIG, &priv->ip6_config, NULL, NM_TYPE_IP6_CONFIG },
+ { NM_DEVICE_DHCP6_CONFIG, &priv->dhcp6_config, NULL, NM_TYPE_DHCP6_CONFIG },
{ NM_DEVICE_STATE, &priv->state },
- { NM_DEVICE_ACTIVE_CONNECTION, &priv->active_connection, demarshal_active_connection },
+ { NM_DEVICE_ACTIVE_CONNECTION, &priv->active_connection, NULL, NM_TYPE_ACTIVE_CONNECTION },
/* The D-Bus interface has this property, but we don't; register
* it so that handle_property_changed() doesn't complain.
@@ -795,35 +635,44 @@ nm_device_class_init (NMDeviceClass *device_class)
G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT);
}
-/**
- * nm_device_new:
- * @connection: the #DBusGConnection
- * @path: the DBus object path of the device
- *
- * Creates a new #NMDevice.
- *
- * Returns: (transfer full): a new device
- **/
-GObject *
-nm_device_new (DBusGConnection *connection, const char *path)
+static GType
+nm_device_gtype_from_dtype (NMDeviceType dtype)
+{
+ switch (dtype) {
+ case NM_DEVICE_TYPE_ETHERNET:
+ return NM_TYPE_DEVICE_ETHERNET;
+ case NM_DEVICE_TYPE_WIFI:
+ return NM_TYPE_DEVICE_WIFI;
+ case NM_DEVICE_TYPE_MODEM:
+ return NM_TYPE_DEVICE_MODEM;
+ case NM_DEVICE_TYPE_BT:
+ return NM_TYPE_DEVICE_BT;
+ case NM_DEVICE_TYPE_WIMAX:
+ return NM_TYPE_DEVICE_WIMAX;
+ case NM_DEVICE_TYPE_INFINIBAND:
+ return NM_TYPE_DEVICE_INFINIBAND;
+ default:
+ g_warning ("Unknown device type %d", dtype);
+ return G_TYPE_INVALID;
+ }
+}
+
+static GType
+nm_device_type_for_path (DBusGConnection *connection,
+ const char *path)
{
DBusGProxy *proxy;
GError *err = NULL;
GValue value = {0,};
- GType dtype = 0;
- NMDevice *device = NULL;
NMDeviceType nm_dtype;
- g_return_val_if_fail (connection != NULL, NULL);
- g_return_val_if_fail (path != NULL, NULL);
-
proxy = dbus_g_proxy_new_for_name (connection,
NM_DBUS_SERVICE,
path,
"org.freedesktop.DBus.Properties");
if (!proxy) {
g_warning ("%s: couldn't create D-Bus object proxy.", __func__);
- return NULL;
+ return G_TYPE_INVALID;
}
if (!dbus_g_proxy_call (proxy,
@@ -832,47 +681,97 @@ nm_device_new (DBusGConnection *connection, const char *path)
G_TYPE_STRING, "DeviceType",
G_TYPE_INVALID,
G_TYPE_VALUE, &value, G_TYPE_INVALID)) {
+ g_object_unref (proxy);
g_warning ("Error in get_property: %s\n", err->message);
g_error_free (err);
- goto out;
}
+ g_object_unref (proxy);
nm_dtype = g_value_get_uint (&value);
- switch (nm_dtype) {
- case NM_DEVICE_TYPE_ETHERNET:
- dtype = NM_TYPE_DEVICE_ETHERNET;
- break;
- case NM_DEVICE_TYPE_WIFI:
- dtype = NM_TYPE_DEVICE_WIFI;
- break;
- case NM_DEVICE_TYPE_MODEM:
- dtype = NM_TYPE_DEVICE_MODEM;
- break;
- case NM_DEVICE_TYPE_BT:
- dtype = NM_TYPE_DEVICE_BT;
- break;
- case NM_DEVICE_TYPE_WIMAX:
- dtype = NM_TYPE_DEVICE_WIMAX;
- break;
- case NM_DEVICE_TYPE_INFINIBAND:
- dtype = NM_TYPE_DEVICE_INFINIBAND;
- break;
- default:
- g_warning ("Unknown device type %d", g_value_get_uint (&value));
- break;
- }
+ return nm_device_gtype_from_dtype (nm_dtype);
+}
+
+/**
+ * nm_device_new:
+ * @connection: the #DBusGConnection
+ * @path: the DBus object path of the device
+ *
+ * Creates a new #NMDevice.
+ *
+ * Returns: (transfer full): a new device
+ **/
+GObject *
+nm_device_new (DBusGConnection *connection, const char *path)
+{
+ GType dtype;
- if (dtype) {
- device = (NMDevice *) g_object_new (dtype,
- NM_OBJECT_DBUS_CONNECTION, connection,
- NM_OBJECT_DBUS_PATH, path,
- NM_DEVICE_DEVICE_TYPE, nm_dtype,
- NULL);
+ g_return_val_if_fail (connection != NULL, NULL);
+ g_return_val_if_fail (path != NULL, NULL);
+
+ dtype = nm_device_type_for_path (connection, path);
+ if (dtype == G_TYPE_INVALID)
+ return NULL;
+
+ return g_object_new (dtype,
+ NM_OBJECT_DBUS_CONNECTION, connection,
+ NM_OBJECT_DBUS_PATH, path,
+ NULL);
+}
+
+typedef struct {
+ DBusGConnection *connection;
+ NMObjectTypeCallbackFunc callback;
+ gpointer user_data;
+} NMDeviceAsyncData;
+
+static void
+async_got_type (DBusGProxy *proxy, DBusGProxyCall *call, gpointer user_data)
+{
+ NMDeviceAsyncData *async_data = user_data;
+ GValue value = G_VALUE_INIT;
+ const char *path = dbus_g_proxy_get_path (proxy);
+ GError *error = NULL;
+ GType type;
+
+ if (dbus_g_proxy_end_call (proxy, call, &error,
+ G_TYPE_VALUE, &value,
+ G_TYPE_INVALID)) {
+ NMDeviceType dtype;
+
+ dtype = g_value_get_uint (&value);
+ type = nm_device_gtype_from_dtype (dtype);
+ } else {
+ g_warning ("%s: could not read properties for %s: %s", __func__, path, error->message);
+ g_error_free (error);
+ type = G_TYPE_INVALID;
}
-out:
+ async_data->callback (type, async_data->user_data);
g_object_unref (proxy);
- return G_OBJECT (device);
+ g_slice_free (NMDeviceAsyncData, async_data);
+}
+
+static void
+nm_device_type_for_path_async (DBusGConnection *connection,
+ const char *path,
+ NMObjectTypeCallbackFunc callback,
+ gpointer user_data)
+{
+ NMDeviceAsyncData *async_data;
+ DBusGProxy *proxy;
+
+ async_data = g_slice_new (NMDeviceAsyncData);
+ async_data->connection = connection;
+ async_data->callback = callback;
+ async_data->user_data = user_data;
+
+ proxy = dbus_g_proxy_new_for_name (connection, NM_DBUS_SERVICE, path,
+ "org.freedesktop.DBus.Properties");
+ dbus_g_proxy_begin_call (proxy, "Get",
+ async_got_type, async_data, NULL,
+ G_TYPE_STRING, NM_DBUS_INTERFACE_DEVICE,
+ G_TYPE_STRING, "DeviceType",
+ G_TYPE_INVALID);
}
/**
@@ -923,9 +822,31 @@ nm_device_get_ip_iface (NMDevice *device)
NMDeviceType
nm_device_get_device_type (NMDevice *self)
{
+ NMDevicePrivate *priv;
+
g_return_val_if_fail (NM_IS_DEVICE (self), NM_DEVICE_TYPE_UNKNOWN);
- return NM_DEVICE_GET_PRIVATE (self)->device_type;
+ priv = NM_DEVICE_GET_PRIVATE (self);
+
+ /* Fill this in if it wasn't set at construct time */
+ if (priv->device_type == NM_DEVICE_TYPE_UNKNOWN) {
+ if (NM_IS_DEVICE_ETHERNET (self))
+ priv->device_type = NM_DEVICE_TYPE_ETHERNET;
+ else if (NM_IS_DEVICE_WIFI (self))
+ priv->device_type = NM_DEVICE_TYPE_WIFI;
+ else if (NM_IS_DEVICE_MODEM (self))
+ priv->device_type = NM_DEVICE_TYPE_MODEM;
+ else if (NM_IS_DEVICE_BT (self))
+ priv->device_type = NM_DEVICE_TYPE_BT;
+ else if (NM_IS_DEVICE_WIMAX (self))
+ priv->device_type = NM_DEVICE_TYPE_WIMAX;
+ else if (NM_IS_DEVICE_INFINIBAND (self))
+ priv->device_type = NM_DEVICE_TYPE_INFINIBAND;
+ else
+ g_warn_if_reached ();
+ }
+
+ return priv->device_type;
}
/**
diff --git a/libnm-glib/nm-object-private.h b/libnm-glib/nm-object-private.h
index 7b14ad694e..08aa525e53 100644
--- a/libnm-glib/nm-object-private.h
+++ b/libnm-glib/nm-object-private.h
@@ -30,12 +30,14 @@
void _nm_object_ensure_inited (NMObject *object);
typedef gboolean (*PropertyMarshalFunc) (NMObject *, GParamSpec *, GValue *, gpointer);
+
typedef GObject * (*NMObjectCreatorFunc) (DBusGConnection *, const char *);
typedef struct {
const char *name;
gpointer field;
PropertyMarshalFunc func;
+ GType object_type;
} NMPropertiesInfo;
@@ -69,4 +71,12 @@ handle_ptr_array_return (GPtrArray *array)
return array;
}
+/* object demarshalling support */
+typedef GType (*NMObjectTypeFunc) (DBusGConnection *, const char *);
+typedef void (*NMObjectTypeCallbackFunc) (GType, gpointer);
+typedef void (*NMObjectTypeAsyncFunc) (DBusGConnection *, const char *, NMObjectTypeCallbackFunc, gpointer);
+
+void _nm_object_register_type_func (GType base_type, NMObjectTypeFunc type_func,
+ NMObjectTypeAsyncFunc type_async_func);
+
#endif /* NM_OBJECT_PRIVATE_H */
diff --git a/libnm-glib/nm-object.c b/libnm-glib/nm-object.c
index 5eb7a0a6fd..dfcb33f352 100644
--- a/libnm-glib/nm-object.c
+++ b/libnm-glib/nm-object.c
@@ -30,6 +30,7 @@
#include "nm-object-private.h"
#include "nm-dbus-glib-types.h"
#include "nm-glib-compat.h"
+#include "nm-types.h"
#define DEBUG 0
@@ -37,8 +38,12 @@ G_DEFINE_ABSTRACT_TYPE (NMObject, nm_object, G_TYPE_OBJECT)
#define NM_OBJECT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_OBJECT, NMObjectPrivate))
+static GHashTable *type_funcs, *type_async_funcs;
+
typedef struct {
PropertyMarshalFunc func;
+ GType object_type;
+
gpointer field;
} PropertyInfo;
@@ -192,6 +197,11 @@ nm_object_class_init (NMObjectClass *nm_object_class)
g_type_class_add_private (nm_object_class, sizeof (NMObjectPrivate));
+ if (!type_funcs) {
+ type_funcs = g_hash_table_new (NULL, NULL);
+ type_async_funcs = g_hash_table_new (NULL, NULL);
+ }
+
/* virtual methods */
object_class->constructor = constructor;
object_class->set_property = set_property;
@@ -311,6 +321,81 @@ _nm_object_queue_notify (NMObject *object, const char *property)
priv->notify_props = g_slist_prepend (priv->notify_props, g_strdup (property));
}
+void
+_nm_object_register_type_func (GType base_type, NMObjectTypeFunc type_func,
+ NMObjectTypeAsyncFunc type_async_func)
+{
+ g_hash_table_insert (type_funcs,
+ GSIZE_TO_POINTER (base_type),
+ type_func);
+ g_hash_table_insert (type_async_funcs,
+ GSIZE_TO_POINTER (base_type),
+ type_async_func);
+}
+
+static GObject *
+_nm_object_create (GType type, DBusGConnection *connection, const char *path)
+{
+ NMObjectTypeFunc type_func;
+
+ type_func = g_hash_table_lookup (type_funcs, GSIZE_TO_POINTER (type));
+ if (type_func)
+ type = type_func (connection, path);
+
+ return g_object_new (type,
+ NM_OBJECT_DBUS_CONNECTION, connection,
+ NM_OBJECT_DBUS_PATH, path,
+ NULL);
+}
+
+typedef void (*NMObjectCreateCallbackFunc) (GObject *, gpointer);
+typedef struct {
+ DBusGConnection *connection;
+ char *path;
+ NMObjectCreateCallbackFunc callback;
+ gpointer user_data;
+} NMObjectTypeAsyncData;
+
+static void
+async_got_type (GType type, gpointer user_data)
+{
+ NMObjectTypeAsyncData *async_data = user_data;
+ GObject *object;
+
+ if (type != G_TYPE_INVALID) {
+ object = g_object_new (type,
+ NM_OBJECT_DBUS_CONNECTION, async_data->connection,
+ NM_OBJECT_DBUS_PATH, async_data->path,
+ NULL);
+ } else
+ object = NULL;
+
+ async_data->callback (object, async_data->user_data);
+
+ g_free (async_data->path);
+ g_slice_free (NMObjectTypeAsyncData, async_data);
+}
+
+static void
+_nm_object_create_async (GType type, DBusGConnection *connection, const char *path,
+ NMObjectCreateCallbackFunc callback, gpointer user_data)
+{
+ NMObjectTypeAsyncFunc type_async_func;
+ NMObjectTypeAsyncData *async_data;
+
+ async_data = g_slice_new (NMObjectTypeAsyncData);
+ async_data->connection = connection;
+ async_data->path = g_strdup (path);
+ async_data->callback = callback;
+ async_data->user_data = user_data;
+
+ type_async_func = g_hash_table_lookup (type_async_funcs, GSIZE_TO_POINTER (type));
+ if (type_async_func)
+ type_async_func (connection, path, async_got_type, async_data);
+ else
+ async_got_type (type, async_data);
+}
+
/* Stolen from dbus-glib */
static char*
wincaps_to_dash (const char *caps)
@@ -333,19 +418,155 @@ wincaps_to_dash (const char *caps)
return g_string_free (str, FALSE);
}
+typedef struct {
+ NMObject *self;
+ PropertyInfo *pi;
+
+ GObject **objects;
+ int length, remaining;
+
+ gboolean array;
+ const char *property_name;
+} ObjectCreatedData;
+
static void
-handle_property_changed (gpointer key, gpointer data, gpointer user_data)
+object_created (GObject *obj, gpointer user_data)
+{
+ ObjectCreatedData *odata = user_data;
+ NMObject *self = odata->self;
+ PropertyInfo *pi = odata->pi;
+
+ /* We assume that on error, the creator_func printed something */
+
+ odata->objects[--odata->remaining] = obj;
+ if (odata->remaining)
+ return;
+
+ if (odata->array) {
+ GPtrArray **array = pi->field;
+ int i;
+
+ if (*array)
+ g_boxed_free (NM_TYPE_OBJECT_ARRAY, *array);
+ *array = g_ptr_array_sized_new (odata->length);
+ for (i = 0; i < odata->length; i++) {
+ if (odata->objects[i])
+ g_ptr_array_add (*array, odata->objects[i]);
+ }
+ } else {
+ GObject **obj_p = pi->field;
+
+ g_clear_object (obj_p);
+ *obj_p = odata->objects[0];
+ }
+
+ if (odata->property_name)
+ _nm_object_queue_notify (self, odata->property_name);
+
+ g_object_unref (self);
+ g_free (odata->objects);
+ g_slice_free (ObjectCreatedData, odata);
+}
+
+static gboolean
+handle_object_property (NMObject *self, const char *property_name, GValue *value,
+ PropertyInfo *pi, gboolean synchronously)
+{
+ NMObjectPrivate *priv = NM_OBJECT_GET_PRIVATE (self);
+ GObject *obj;
+ const char *path;
+ ObjectCreatedData *odata;
+
+ odata = g_slice_new (ObjectCreatedData);
+ odata->self = g_object_ref (self);
+ odata->pi = pi;
+ odata->objects = g_new (GObject *, 1);
+ odata->length = odata->remaining = 1;
+ odata->array = FALSE;
+ odata->property_name = property_name;
+
+ path = g_value_get_boxed (value);
+ if (!strcmp (path, "/")) {
+ object_created (NULL, odata);
+ return TRUE;
+ }
+
+ obj = G_OBJECT (_nm_object_cache_get (path));
+ if (obj) {
+ object_created (obj, odata);
+ return TRUE;
+ } else if (synchronously) {
+ obj = _nm_object_create (pi->object_type, priv->connection, path);
+ object_created (obj, odata);
+ return obj != NULL;
+ } else {
+ _nm_object_create_async (pi->object_type, priv->connection, path,
+ object_created, odata);
+ /* Assume success */
+ return TRUE;
+ }
+}
+
+static gboolean
+handle_object_array_property (NMObject *self, const char *property_name, GValue *value,
+ PropertyInfo *pi, gboolean synchronously)
+{
+ NMObjectPrivate *priv = NM_OBJECT_GET_PRIVATE (self);
+ GObject *obj;
+ GPtrArray *paths;
+ GPtrArray **array = pi->field;
+ const char *path;
+ ObjectCreatedData *odata;
+ int i;
+
+ paths = g_value_get_boxed (value);
+
+ odata = g_slice_new (ObjectCreatedData);
+ odata->self = g_object_ref (self);
+ odata->pi = pi;
+ odata->objects = g_new0 (GObject *, paths->len);
+ odata->length = odata->remaining = paths->len;
+ odata->array = TRUE;
+ odata->property_name = property_name;
+
+ for (i = 0; i < paths->len; i++) {
+ path = paths->pdata[i];
+ if (!strcmp (path, "/")) {
+ /* FIXME: can't happen? */
+ continue;
+ }
+
+ obj = G_OBJECT (_nm_object_cache_get (path));
+ if (obj) {
+ object_created (obj, odata);
+ } else if (synchronously) {
+ obj = _nm_object_create (pi->object_type, priv->connection, path);
+ object_created (obj, odata);
+ } else {
+ _nm_object_create_async (pi->object_type, priv->connection, path,
+ object_created, odata);
+ }
+ }
+
+ if (!synchronously) {
+ /* Assume success */
+ return TRUE;
+ }
+
+ return *array && ((*array)->len == paths->len);
+}
+
+static void
+handle_property_changed (NMObject *self, const char *dbus_name, GValue *value, gboolean synchronously)
{
- NMObject *self = NM_OBJECT (user_data);
NMObjectPrivate *priv = NM_OBJECT_GET_PRIVATE (self);
char *prop_name;
PropertyInfo *pi;
GParamSpec *pspec;
gboolean success = FALSE, found = FALSE;
GSList *iter;
- GValue *value = data;
- prop_name = wincaps_to_dash ((char *) key);
+ prop_name = wincaps_to_dash (dbus_name);
/* Iterate through the object and its parents to find the property */
for (iter = priv->property_tables; iter; iter = g_slist_next (iter)) {
@@ -377,13 +598,18 @@ handle_property_changed (gpointer key, gpointer data, gpointer user_data)
goto out;
}
- /* Handle NULL object paths */
- if (G_VALUE_HOLDS (value, DBUS_TYPE_G_OBJECT_PATH)) {
- if (g_strcmp0 (g_value_get_boxed (value), "/") == 0)
- value = NULL;
- }
+ if (pi->object_type) {
+ if (G_VALUE_HOLDS (value, DBUS_TYPE_G_OBJECT_PATH))
+ success = handle_object_property (self, pspec->name, value, pi, synchronously);
+ else if (G_VALUE_HOLDS (value, DBUS_TYPE_G_ARRAY_OF_OBJECT_PATH))
+ success = handle_object_array_property (self, pspec->name, value, pi, synchronously);
+ else {
+ g_warn_if_reached ();
+ goto out;
+ }
+ } else
+ success = (*(pi->func)) (self, pspec, value, pi->field);
- success = (*(pi->func)) (self, pspec, value, pi->field);
if (!success) {
g_warning ("%s: failed to update property '%s' of object type %s.",
__func__,
@@ -398,7 +624,12 @@ out:
void
_nm_object_process_properties_changed (NMObject *self, GHashTable *properties)
{
- g_hash_table_foreach (properties, handle_property_changed, self);
+ GHashTableIter iter;
+ gpointer name, value;
+
+ g_hash_table_iter_init (&iter, properties);
+ while (g_hash_table_iter_next (&iter, &name, &value))
+ handle_property_changed (self, name, value, FALSE);
}
static void
@@ -509,6 +740,7 @@ _nm_object_register_properties (NMObject *object,
pi = g_malloc0 (sizeof (PropertyInfo));
pi->func = tmp->func ? tmp->func : demarshal_generic;
+ pi->object_type = tmp->object_type;
pi->field = tmp->field;
g_hash_table_insert (instance, g_strdup (tmp->name), pi);
}
@@ -591,7 +823,7 @@ _nm_object_reload_property (NMObject *object,
return;
}
- handle_property_changed ((gpointer)prop_name, &value, object);
+ handle_property_changed (object, prop_name, &value, TRUE);
g_value_unset (&value);
}