[PATCH] libnm-glib property handling simplifications



(depends on the previous patches)
>From 3d45ef3e5117c42529755aaa5fdcad085726ec1a Mon Sep 17 00:00:00 2001
From: Dan Winship <danw gnome org>
Date: Fri, 20 Jan 2012 07:52:17 -0500
Subject: [PATCH 06/12] libnm-glib: simplify and genericize property
 declaration

Rename _nm_object_handle_properties_changed(), etc, to be about
properties in general, rather than just property changes.

Interpret func==NULL in NMPropertiesInfo as meaning "use
_nm_object_demarshal_generic", and then reorder the fields so that you
can just leave that field out in the declarations when it's NULL.

Add a way to register properties that exist in D-Bus but aren't
tracked by the NMObjects, and use that for NMDevice's D-Bus Ip4Address
property, replacing the existing hack.

Also add a few other missing properties noticed along the way.
---
 libnm-glib/nm-access-point.c      |   30 ++++----
 libnm-glib/nm-active-connection.c |   26 +++---
 libnm-glib/nm-client.c            |   32 ++++----
 libnm-glib/nm-device-bt.c         |   18 ++--
 libnm-glib/nm-device-ethernet.c   |   20 +++---
 libnm-glib/nm-device-infiniband.c |   16 ++--
 libnm-glib/nm-device-modem.c      |   16 ++--
 libnm-glib/nm-device-wifi.c       |   24 +++---
 libnm-glib/nm-device-wimax.c      |   26 +++---
 libnm-glib/nm-device.c            |   48 ++++++------
 libnm-glib/nm-dhcp4-config.c      |   14 ++--
 libnm-glib/nm-dhcp6-config.c      |   14 ++--
 libnm-glib/nm-ip4-config.c        |   22 +++---
 libnm-glib/nm-ip6-config.c        |   20 +++---
 libnm-glib/nm-object-private.h    |   14 ++--
 libnm-glib/nm-object.c            |  159 ++++++++++++++++++++-----------------
 libnm-glib/nm-vpn-connection.c    |   18 ++++
 libnm-glib/nm-wimax-nsp.c         |   16 ++--
 18 files changed, 283 insertions(+), 250 deletions(-)

diff --git a/libnm-glib/nm-access-point.c b/libnm-glib/nm-access-point.c
index 1632059..2a5d20c 100644
--- a/libnm-glib/nm-access-point.c
+++ b/libnm-glib/nm-access-point.c
@@ -593,25 +593,25 @@ demarshal_ssid (NMObject *object, GParamSpec *pspec, GValue *value, gpointer fie
 }
 
 static void
-register_for_property_changed (NMAccessPoint *ap)
+register_properties (NMAccessPoint *ap)
 {
 	NMAccessPointPrivate *priv = NM_ACCESS_POINT_GET_PRIVATE (ap);
-	const NMPropertiesChangedInfo property_changed_info[] = {
-		{ NM_ACCESS_POINT_FLAGS,       _nm_object_demarshal_generic, &priv->flags },
-		{ NM_ACCESS_POINT_WPA_FLAGS,   _nm_object_demarshal_generic, &priv->wpa_flags },
-		{ NM_ACCESS_POINT_RSN_FLAGS,   _nm_object_demarshal_generic, &priv->rsn_flags },
-		{ NM_ACCESS_POINT_SSID,        demarshal_ssid,               &priv->ssid },
-		{ NM_ACCESS_POINT_FREQUENCY,   _nm_object_demarshal_generic, &priv->frequency },
-		{ NM_ACCESS_POINT_HW_ADDRESS,  _nm_object_demarshal_generic, &priv->bssid },
-		{ NM_ACCESS_POINT_MODE,        _nm_object_demarshal_generic, &priv->mode },
-		{ NM_ACCESS_POINT_MAX_BITRATE, _nm_object_demarshal_generic, &priv->max_bitrate },
-		{ NM_ACCESS_POINT_STRENGTH,    _nm_object_demarshal_generic, &priv->strength },
+	const NMPropertiesInfo property_info[] = {
+		{ NM_ACCESS_POINT_FLAGS,       &priv->flags },
+		{ NM_ACCESS_POINT_WPA_FLAGS,   &priv->wpa_flags },
+		{ NM_ACCESS_POINT_RSN_FLAGS,   &priv->rsn_flags },
+		{ NM_ACCESS_POINT_SSID,        &priv->ssid, demarshal_ssid },
+		{ NM_ACCESS_POINT_FREQUENCY,   &priv->frequency },
+		{ NM_ACCESS_POINT_HW_ADDRESS,  &priv->bssid },
+		{ NM_ACCESS_POINT_MODE,        &priv->mode },
+		{ NM_ACCESS_POINT_MAX_BITRATE, &priv->max_bitrate },
+		{ NM_ACCESS_POINT_STRENGTH,    &priv->strength },
 		{ NULL },
 	};
 
-	_nm_object_handle_properties_changed (NM_OBJECT (ap),
-	                                     priv->proxy,
-	                                     property_changed_info);
+	_nm_object_register_properties (NM_OBJECT (ap),
+	                                priv->proxy,
+	                                property_info);
 }
 
 static GObject*
@@ -635,7 +635,7 @@ constructor (GType type,
 									    nm_object_get_path (object),
 									    NM_DBUS_INTERFACE_ACCESS_POINT);
 
-	register_for_property_changed (NM_ACCESS_POINT (object));
+	register_properties (NM_ACCESS_POINT (object));
 
 	return G_OBJECT (object);
 }
diff --git a/libnm-glib/nm-active-connection.c b/libnm-glib/nm-active-connection.c
index 4b2c642..2c37e71 100644
--- a/libnm-glib/nm-active-connection.c
+++ b/libnm-glib/nm-active-connection.c
@@ -410,22 +410,24 @@ demarshal_devices (NMObject *object, GParamSpec *pspec, GValue *value, gpointer
 }
 
 static void
-register_for_property_changed (NMActiveConnection *connection)
+register_properties (NMActiveConnection *connection)
 {
 	NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (connection);
-	const NMPropertiesChangedInfo property_changed_info[] = {
-		{ NM_ACTIVE_CONNECTION_CONNECTION,          _nm_object_demarshal_generic, &priv->connection },
-		{ NM_ACTIVE_CONNECTION_SPECIFIC_OBJECT,     _nm_object_demarshal_generic, &priv->specific_object },
-		{ NM_ACTIVE_CONNECTION_DEVICES,             demarshal_devices,           &priv->devices },
-		{ NM_ACTIVE_CONNECTION_STATE,               _nm_object_demarshal_generic, &priv->state },
-		{ NM_ACTIVE_CONNECTION_DEFAULT,             _nm_object_demarshal_generic, &priv->is_default },
-		{ NM_ACTIVE_CONNECTION_DEFAULT6,            _nm_object_demarshal_generic, &priv->is_default6 },
+	const NMPropertiesInfo property_info[] = {
+		{ 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_STATE,               &priv->state },
+		{ NM_ACTIVE_CONNECTION_DEFAULT,             &priv->is_default },
+		{ NM_ACTIVE_CONNECTION_DEFAULT6,            &priv->is_default6 },
+		{ NM_ACTIVE_CONNECTION_MASTER,              &priv->master },
 		{ NULL },
 	};
 
-	_nm_object_handle_properties_changed (NM_OBJECT (connection),
-	                                     priv->proxy,
-	                                     property_changed_info);
+	_nm_object_register_properties (NM_OBJECT (connection),
+	                                priv->proxy,
+	                                property_info);
 }
 
 static GObject*
@@ -449,7 +451,7 @@ constructor (GType type,
 									    nm_object_get_path (object),
 									    NM_DBUS_INTERFACE_ACTIVE_CONNECTION);
 
-	register_for_property_changed (NM_ACTIVE_CONNECTION (object));
+	register_properties (NM_ACTIVE_CONNECTION (object));
 
 	return G_OBJECT (object);
 }
diff --git a/libnm-glib/nm-client.c b/libnm-glib/nm-client.c
index 897de6c..42517c8 100644
--- a/libnm-glib/nm-client.c
+++ b/libnm-glib/nm-client.c
@@ -314,26 +314,26 @@ demarshal_active_connections (NMObject *object,
 }
 
 static void
-register_for_property_changed (NMClient *client)
+register_properties (NMClient *client)
 {
 	NMClientPrivate *priv = NM_CLIENT_GET_PRIVATE (client);
-	const NMPropertiesChangedInfo property_changed_info[] = {
-		{ NM_CLIENT_VERSION,                   _nm_object_demarshal_generic,  &priv->version },
-		{ NM_CLIENT_STATE,                     _nm_object_demarshal_generic,  &priv->state },
-		{ NM_CLIENT_NETWORKING_ENABLED,        _nm_object_demarshal_generic,  &priv->networking_enabled },
-		{ NM_CLIENT_WIRELESS_ENABLED,          _nm_object_demarshal_generic,  &priv->wireless_enabled },
-		{ NM_CLIENT_WIRELESS_HARDWARE_ENABLED, _nm_object_demarshal_generic,  &priv->wireless_hw_enabled },
-		{ NM_CLIENT_WWAN_ENABLED,              _nm_object_demarshal_generic,  &priv->wwan_enabled },
-		{ NM_CLIENT_WWAN_HARDWARE_ENABLED,     _nm_object_demarshal_generic,  &priv->wwan_hw_enabled },
-		{ NM_CLIENT_WIMAX_ENABLED,             _nm_object_demarshal_generic,  &priv->wimax_enabled },
-		{ NM_CLIENT_WIMAX_HARDWARE_ENABLED,    _nm_object_demarshal_generic,  &priv->wimax_hw_enabled },
-		{ NM_CLIENT_ACTIVE_CONNECTIONS,        demarshal_active_connections, &priv->active_connections },
+	const NMPropertiesInfo property_info[] = {
+		{ NM_CLIENT_VERSION,                   &priv->version },
+		{ NM_CLIENT_STATE,                     &priv->state },
+		{ NM_CLIENT_NETWORKING_ENABLED,        &priv->networking_enabled },
+		{ NM_CLIENT_WIRELESS_ENABLED,          &priv->wireless_enabled },
+		{ NM_CLIENT_WIRELESS_HARDWARE_ENABLED, &priv->wireless_hw_enabled },
+		{ NM_CLIENT_WWAN_ENABLED,              &priv->wwan_enabled },
+		{ 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 },
 		{ NULL },
 	};
 
-	_nm_object_handle_properties_changed (NM_OBJECT (client),
-	                                     priv->client_proxy,
-	                                     property_changed_info);
+	_nm_object_register_properties (NM_OBJECT (client),
+	                                priv->client_proxy,
+	                                property_info);
 }
 
 #define NM_AUTH_PERMISSION_ENABLE_DISABLE_NETWORK     "org.freedesktop.NetworkManager.enable-disable-network"
@@ -1385,7 +1385,7 @@ constructor (GType type,
 										   nm_object_get_path (object),
 										   NM_DBUS_INTERFACE);
 
-	register_for_property_changed (NM_CLIENT (object));
+	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,
diff --git a/libnm-glib/nm-device-bt.c b/libnm-glib/nm-device-bt.c
index 14c21ae..960f8ce 100644
--- a/libnm-glib/nm-device-bt.c
+++ b/libnm-glib/nm-device-bt.c
@@ -230,19 +230,19 @@ nm_device_bt_init (NMDeviceBt *device)
 }
 
 static void
-register_for_property_changed (NMDeviceBt *device)
+register_properties (NMDeviceBt *device)
 {
 	NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (device);
-	const NMPropertiesChangedInfo property_changed_info[] = {
-		{ NM_DEVICE_BT_HW_ADDRESS,   _nm_object_demarshal_generic, &priv->hw_address },
-		{ NM_DEVICE_BT_NAME,         _nm_object_demarshal_generic, &priv->name },
-		{ NM_DEVICE_BT_CAPABILITIES, _nm_object_demarshal_generic, &priv->bt_capabilities },
+	const NMPropertiesInfo property_info[] = {
+		{ NM_DEVICE_BT_HW_ADDRESS,   &priv->hw_address },
+		{ NM_DEVICE_BT_NAME,         &priv->name },
+		{ NM_DEVICE_BT_CAPABILITIES, &priv->bt_capabilities },
 		{ NULL },
 	};
 
-	_nm_object_handle_properties_changed (NM_OBJECT (device),
-	                                     priv->proxy,
-	                                     property_changed_info);
+	_nm_object_register_properties (NM_OBJECT (device),
+	                                priv->proxy,
+	                                property_info);
 }
 
 static GObject*
@@ -263,7 +263,7 @@ constructor (GType type,
 		                                         nm_object_get_path (NM_OBJECT (object)),
 		                                         NM_DBUS_INTERFACE_DEVICE_BLUETOOTH);
 
-		register_for_property_changed (NM_DEVICE_BT (object));
+		register_properties (NM_DEVICE_BT (object));
 	}
 
 	return object;
diff --git a/libnm-glib/nm-device-ethernet.c b/libnm-glib/nm-device-ethernet.c
index 912ba6a..1eb8189 100644
--- a/libnm-glib/nm-device-ethernet.c
+++ b/libnm-glib/nm-device-ethernet.c
@@ -247,20 +247,20 @@ nm_device_ethernet_init (NMDeviceEthernet *device)
 }
 
 static void
-register_for_property_changed (NMDeviceEthernet *device)
+register_properties (NMDeviceEthernet *device)
 {
 	NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (device);
-	const NMPropertiesChangedInfo property_changed_info[] = {
-		{ NM_DEVICE_ETHERNET_HW_ADDRESS,           _nm_object_demarshal_generic, &priv->hw_address },
-		{ NM_DEVICE_ETHERNET_PERMANENT_HW_ADDRESS, _nm_object_demarshal_generic, &priv->perm_hw_address },
-		{ NM_DEVICE_ETHERNET_SPEED,                _nm_object_demarshal_generic, &priv->speed },
-		{ NM_DEVICE_ETHERNET_CARRIER,              _nm_object_demarshal_generic, &priv->carrier },
+	const NMPropertiesInfo property_info[] = {
+		{ NM_DEVICE_ETHERNET_HW_ADDRESS,           &priv->hw_address },
+		{ NM_DEVICE_ETHERNET_PERMANENT_HW_ADDRESS, &priv->perm_hw_address },
+		{ NM_DEVICE_ETHERNET_SPEED,                &priv->speed },
+		{ NM_DEVICE_ETHERNET_CARRIER,              &priv->carrier },
 		{ NULL },
 	};
 
-	_nm_object_handle_properties_changed (NM_OBJECT (device),
-	                                     priv->proxy,
-	                                     property_changed_info);
+	_nm_object_register_properties (NM_OBJECT (device),
+	                                priv->proxy,
+	                                property_info);
 }
 
 static GObject*
@@ -284,7 +284,7 @@ constructor (GType type,
 	                                         nm_object_get_path (NM_OBJECT (object)),
 	                                         NM_DBUS_INTERFACE_DEVICE_WIRED);
 
-	register_for_property_changed (NM_DEVICE_ETHERNET (object));
+	register_properties (NM_DEVICE_ETHERNET (object));
 
 	return object;
 }
diff --git a/libnm-glib/nm-device-infiniband.c b/libnm-glib/nm-device-infiniband.c
index 0887f63..576f7ee 100644
--- a/libnm-glib/nm-device-infiniband.c
+++ b/libnm-glib/nm-device-infiniband.c
@@ -175,18 +175,18 @@ nm_device_infiniband_init (NMDeviceInfiniband *device)
 }
 
 static void
-register_for_property_changed (NMDeviceInfiniband *device)
+register_properties (NMDeviceInfiniband *device)
 {
 	NMDeviceInfinibandPrivate *priv = NM_DEVICE_INFINIBAND_GET_PRIVATE (device);
-	const NMPropertiesChangedInfo property_changed_info[] = {
-		{ NM_DEVICE_INFINIBAND_HW_ADDRESS, _nm_object_demarshal_generic, &priv->hw_address },
-		{ NM_DEVICE_INFINIBAND_CARRIER,    _nm_object_demarshal_generic, &priv->carrier },
+	const NMPropertiesInfo property_info[] = {
+		{ NM_DEVICE_INFINIBAND_HW_ADDRESS, &priv->hw_address },
+		{ NM_DEVICE_INFINIBAND_CARRIER,    &priv->carrier },
 		{ NULL },
 	};
 
-	_nm_object_handle_properties_changed (NM_OBJECT (device),
-	                                      priv->proxy,
-	                                      property_changed_info);
+	_nm_object_register_properties (NM_OBJECT (device),
+	                                priv->proxy,
+	                                property_info);
 }
 
 static GObject*
@@ -210,7 +210,7 @@ constructor (GType type,
 	                                         nm_object_get_path (NM_OBJECT (object)),
 	                                         NM_DBUS_INTERFACE_DEVICE_INFINIBAND);
 
-	register_for_property_changed (NM_DEVICE_INFINIBAND (object));
+	register_properties (NM_DEVICE_INFINIBAND (object));
 
 	return object;
 }
diff --git a/libnm-glib/nm-device-modem.c b/libnm-glib/nm-device-modem.c
index e71e930..a339cd4 100644
--- a/libnm-glib/nm-device-modem.c
+++ b/libnm-glib/nm-device-modem.c
@@ -151,18 +151,18 @@ connection_valid (NMDevice *device, NMConnection *connection)
 /*******************************************************************/
 
 static void
-register_for_property_changed (NMDeviceModem *device)
+register_properties (NMDeviceModem *device)
 {
 	NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE (device);
-	const NMPropertiesChangedInfo property_changed_info[] = {
-		{ NM_DEVICE_MODEM_MODEM_CAPABILITIES,   _nm_object_demarshal_generic, &priv->caps },
-		{ NM_DEVICE_MODEM_CURRENT_CAPABILITIES, _nm_object_demarshal_generic, &priv->current_caps },
+	const NMPropertiesInfo property_info[] = {
+		{ NM_DEVICE_MODEM_MODEM_CAPABILITIES,   &priv->caps },
+		{ NM_DEVICE_MODEM_CURRENT_CAPABILITIES, &priv->current_caps },
 		{ NULL },
 	};
 
-	_nm_object_handle_properties_changed (NM_OBJECT (device),
-	                                      priv->proxy,
-	                                      property_changed_info);
+	_nm_object_register_properties (NM_OBJECT (device),
+	                                priv->proxy,
+	                                property_info);
 }
 
 static GObject*
@@ -184,7 +184,7 @@ constructor (GType type,
 		                                         nm_object_get_path (NM_OBJECT (object)),
 		                                         NM_DBUS_INTERFACE_DEVICE_MODEM);
 
-		register_for_property_changed (NM_DEVICE_MODEM (object));
+		register_properties (NM_DEVICE_MODEM (object));
 	}
 
 	return object;
diff --git a/libnm-glib/nm-device-wifi.c b/libnm-glib/nm-device-wifi.c
index 9b87a52..6ac9181 100644
--- a/libnm-glib/nm-device-wifi.c
+++ b/libnm-glib/nm-device-wifi.c
@@ -667,22 +667,22 @@ demarshal_active_ap (NMObject *object, GParamSpec *pspec, GValue *value, gpointe
 }
 
 static void
-register_for_property_changed (NMDeviceWifi *device)
+register_properties (NMDeviceWifi *device)
 {
 	NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (device);
-	const NMPropertiesChangedInfo property_changed_info[] = {
-		{ NM_DEVICE_WIFI_HW_ADDRESS,           _nm_object_demarshal_generic, &priv->hw_address },
-		{ NM_DEVICE_WIFI_PERMANENT_HW_ADDRESS, _nm_object_demarshal_generic, &priv->perm_hw_address },
-		{ NM_DEVICE_WIFI_MODE,                 _nm_object_demarshal_generic, &priv->mode },
-		{ NM_DEVICE_WIFI_BITRATE,              _nm_object_demarshal_generic, &priv->rate },
-		{ NM_DEVICE_WIFI_ACTIVE_ACCESS_POINT,  demarshal_active_ap,         &priv->active_ap },
-		{ NM_DEVICE_WIFI_CAPABILITIES,         _nm_object_demarshal_generic, &priv->wireless_caps },
+	const NMPropertiesInfo property_info[] = {
+		{ NM_DEVICE_WIFI_HW_ADDRESS,           &priv->hw_address },
+		{ 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_CAPABILITIES,         &priv->wireless_caps },
 		{ NULL },
 	};
 
-	_nm_object_handle_properties_changed (NM_OBJECT (device),
-	                                     priv->proxy,
-	                                     property_changed_info);
+	_nm_object_register_properties (NM_OBJECT (device),
+	                                priv->proxy,
+	                                property_info);
 }
 
 static GObject*
@@ -720,7 +720,7 @@ constructor (GType type,
 						    G_CALLBACK (access_point_removed_proxy),
 						    object, NULL);
 
-	register_for_property_changed (NM_DEVICE_WIFI (object));
+	register_properties (NM_DEVICE_WIFI (object));
 
 	g_signal_connect (NM_DEVICE (object),
 	                  "notify::" NM_DEVICE_STATE,
diff --git a/libnm-glib/nm-device-wimax.c b/libnm-glib/nm-device-wimax.c
index f83d413..d5e3a22 100644
--- a/libnm-glib/nm-device-wimax.c
+++ b/libnm-glib/nm-device-wimax.c
@@ -658,23 +658,23 @@ demarshal_active_nsp (NMObject *object, GParamSpec *pspec, GValue *value, gpoint
 }
 
 static void
-register_for_property_changed (NMDeviceWimax *wimax)
+register_properties (NMDeviceWimax *wimax)
 {
 	NMDeviceWimaxPrivate *priv = NM_DEVICE_WIMAX_GET_PRIVATE (wimax);
-	const NMPropertiesChangedInfo property_changed_info[] = {
-		{ NM_DEVICE_WIMAX_HW_ADDRESS, _nm_object_demarshal_generic, &priv->hw_address },
-		{ NM_DEVICE_WIMAX_ACTIVE_NSP, demarshal_active_nsp, &priv->active_nsp },
-		{ NM_DEVICE_WIMAX_CENTER_FREQUENCY, _nm_object_demarshal_generic, &priv->center_freq },
-		{ NM_DEVICE_WIMAX_RSSI, _nm_object_demarshal_generic, &priv->rssi },
-		{ NM_DEVICE_WIMAX_CINR, _nm_object_demarshal_generic, &priv->cinr },
-		{ NM_DEVICE_WIMAX_TX_POWER, _nm_object_demarshal_generic, &priv->tx_power },
-		{ NM_DEVICE_WIMAX_BSID, _nm_object_demarshal_generic, &priv->bsid },
+	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_CENTER_FREQUENCY, &priv->center_freq },
+		{ NM_DEVICE_WIMAX_RSSI, &priv->rssi },
+		{ NM_DEVICE_WIMAX_CINR, &priv->cinr },
+		{ NM_DEVICE_WIMAX_TX_POWER, &priv->tx_power },
+		{ NM_DEVICE_WIMAX_BSID, &priv->bsid },
 		{ NULL },
 	};
 
-	_nm_object_handle_properties_changed (NM_OBJECT (wimax),
-										  priv->proxy,
-										  property_changed_info);
+	_nm_object_register_properties (NM_OBJECT (wimax),
+	                                priv->proxy,
+	                                property_info);
 }
 
 static GObject*
@@ -712,7 +712,7 @@ constructor (GType type,
 								 G_CALLBACK (nsp_removed_proxy),
 								 object, NULL);
 
-	register_for_property_changed (NM_DEVICE_WIMAX (object));
+	register_properties (NM_DEVICE_WIMAX (object));
 
 	g_signal_connect (object,
 	                  "notify::" NM_DEVICE_STATE,
diff --git a/libnm-glib/nm-device.c b/libnm-glib/nm-device.c
index 6b783dc..d051a39 100644
--- a/libnm-glib/nm-device.c
+++ b/libnm-glib/nm-device.c
@@ -293,28 +293,35 @@ demarshal_active_connection (NMObject *object, GParamSpec *pspec, GValue *value,
 }
 
 static void
-register_for_property_changed (NMDevice *device)
+register_properties (NMDevice *device)
 {
 	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (device);
-	const NMPropertiesChangedInfo property_changed_info[] = {
-		{ NM_DEVICE_UDI,              _nm_object_demarshal_generic, &priv->udi },
-		{ NM_DEVICE_INTERFACE,        _nm_object_demarshal_generic, &priv->iface },
-		{ NM_DEVICE_IP_INTERFACE,     _nm_object_demarshal_generic, &priv->ip_iface },
-		{ NM_DEVICE_DRIVER,           _nm_object_demarshal_generic, &priv->driver },
-		{ NM_DEVICE_CAPABILITIES,     _nm_object_demarshal_generic, &priv->capabilities },
-		{ NM_DEVICE_MANAGED,          _nm_object_demarshal_generic, &priv->managed },
-		{ NM_DEVICE_FIRMWARE_MISSING, _nm_object_demarshal_generic, &priv->firmware_missing },
-		{ NM_DEVICE_IP4_CONFIG,       demarshal_ip4_config,         &priv->ip4_config },
-		{ NM_DEVICE_DHCP4_CONFIG,     demarshal_dhcp4_config,       &priv->dhcp4_config },
-		{ NM_DEVICE_IP6_CONFIG,       demarshal_ip6_config,         &priv->ip6_config },
-		{ NM_DEVICE_DHCP6_CONFIG,     demarshal_dhcp6_config,       &priv->dhcp6_config },
-		{ NM_DEVICE_ACTIVE_CONNECTION,demarshal_active_connection,  &priv->active_connection },
+	const NMPropertiesInfo property_info[] = {
+		{ NM_DEVICE_UDI,               &priv->udi },
+		{ NM_DEVICE_INTERFACE,         &priv->iface },
+		{ NM_DEVICE_IP_INTERFACE,      &priv->ip_iface },
+		{ NM_DEVICE_DRIVER,            &priv->driver },
+		{ 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_STATE,             &priv->state },
+		{ NM_DEVICE_ACTIVE_CONNECTION, &priv->active_connection, demarshal_active_connection },
+
+		/* The D-Bus interface has this property, but we don't; register
+		 * it so that handle_property_changed() doesn't complain.
+		 */
+		{ "ip4-address", NULL },
+
 		{ NULL },
 	};
 
-	_nm_object_handle_properties_changed (NM_OBJECT (device),
-	                                     priv->proxy,
-	                                     property_changed_info);
+	_nm_object_register_properties (NM_OBJECT (device),
+	                                priv->proxy,
+	                                property_info);
 }
 
 static void
@@ -356,11 +363,6 @@ get_all_cb (DBusGProxy *proxy, DBusGProxyCall *call, gpointer user_data)
 	}
 	g_object_unref (proxy);
 
-	/* Hack: libnm-glib's NMDevice doesn't have ip4-address property. Remove
-	 * it from the hash to prevent warnings.
-	 */
-	g_hash_table_remove (props, "Ip4Address");
-
 	_nm_object_process_properties_changed (NM_OBJECT (self), props);
 	g_hash_table_destroy (props);
 
@@ -409,7 +411,7 @@ constructor (GType type,
 											 nm_object_get_path (object),
 											 NM_DBUS_INTERFACE_DEVICE);
 
-	register_for_property_changed (NM_DEVICE (object));
+	register_properties (NM_DEVICE (object));
 
 	/* Get initial properties, so that we have all properties set even if
 	 * no PropertiesChanged signal is received.
diff --git a/libnm-glib/nm-dhcp4-config.c b/libnm-glib/nm-dhcp4-config.c
index 8299de0..e3fe2c6 100644
--- a/libnm-glib/nm-dhcp4-config.c
+++ b/libnm-glib/nm-dhcp4-config.c
@@ -77,17 +77,17 @@ demarshal_dhcp4_options (NMObject *object, GParamSpec *pspec, GValue *value, gpo
 }
 
 static void
-register_for_property_changed (NMDHCP4Config *config)
+register_properties (NMDHCP4Config *config)
 {
 	NMDHCP4ConfigPrivate *priv = NM_DHCP4_CONFIG_GET_PRIVATE (config);
-	const NMPropertiesChangedInfo property_changed_info[] = {
-		{ NM_DHCP4_CONFIG_OPTIONS,   demarshal_dhcp4_options,  &priv->options },
+	const NMPropertiesInfo property_info[] = {
+		{ NM_DHCP4_CONFIG_OPTIONS,   &priv->options, demarshal_dhcp4_options },
 		{ NULL },
 	};
 
-	_nm_object_handle_properties_changed (NM_OBJECT (config),
-	                                     priv->proxy,
-	                                     property_changed_info);
+	_nm_object_register_properties (NM_OBJECT (config),
+	                                priv->proxy,
+	                                property_info);
 }
 
 static GObject*
@@ -115,7 +115,7 @@ constructor (GType type,
 										   nm_object_get_path (object),
 										   NM_DBUS_INTERFACE_DHCP4_CONFIG);
 
-	register_for_property_changed (NM_DHCP4_CONFIG (object));
+	register_properties (NM_DHCP4_CONFIG (object));
 
 	return G_OBJECT (object);
 }
diff --git a/libnm-glib/nm-dhcp6-config.c b/libnm-glib/nm-dhcp6-config.c
index 00698ed..c282a27 100644
--- a/libnm-glib/nm-dhcp6-config.c
+++ b/libnm-glib/nm-dhcp6-config.c
@@ -77,17 +77,17 @@ demarshal_dhcp6_options (NMObject *object, GParamSpec *pspec, GValue *value, gpo
 }
 
 static void
-register_for_property_changed (NMDHCP6Config *config)
+register_properties (NMDHCP6Config *config)
 {
 	NMDHCP6ConfigPrivate *priv = NM_DHCP6_CONFIG_GET_PRIVATE (config);
-	const NMPropertiesChangedInfo property_changed_info[] = {
-		{ NM_DHCP6_CONFIG_OPTIONS,   demarshal_dhcp6_options,  &priv->options },
+	const NMPropertiesInfo property_info[] = {
+		{ NM_DHCP6_CONFIG_OPTIONS,   &priv->options, demarshal_dhcp6_options },
 		{ NULL },
 	};
 
-	_nm_object_handle_properties_changed (NM_OBJECT (config),
-	                                     priv->proxy,
-	                                     property_changed_info);
+	_nm_object_register_properties (NM_OBJECT (config),
+	                                priv->proxy,
+	                                property_info);
 }
 
 static GObject*
@@ -115,7 +115,7 @@ constructor (GType type,
 										   nm_object_get_path (object),
 										   NM_DBUS_INTERFACE_DHCP6_CONFIG);
 
-	register_for_property_changed (NM_DHCP6_CONFIG (object));
+	register_properties (NM_DHCP6_CONFIG (object));
 
 	return G_OBJECT (object);
 }
diff --git a/libnm-glib/nm-ip4-config.c b/libnm-glib/nm-ip4-config.c
index a72fa89..7706d05 100644
--- a/libnm-glib/nm-ip4-config.c
+++ b/libnm-glib/nm-ip4-config.c
@@ -115,21 +115,21 @@ demarshal_ip4_routes_array (NMObject *object, GParamSpec *pspec, GValue *value,
 }
 
 static void
-register_for_property_changed (NMIP4Config *config)
+register_properties (NMIP4Config *config)
 {
 	NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config);
-	const NMPropertiesChangedInfo property_changed_info[] = {
-		{ NM_IP4_CONFIG_ADDRESSES,    demarshal_ip4_address_array,  &priv->addresses },
-		{ NM_IP4_CONFIG_NAMESERVERS,  demarshal_ip4_array,          &priv->nameservers },
-		{ NM_IP4_CONFIG_DOMAINS,      demarshal_domains,            &priv->domains },
-		{ NM_IP4_CONFIG_ROUTES,       demarshal_ip4_routes_array,   &priv->routes },
-		{ NM_IP4_CONFIG_WINS_SERVERS, demarshal_ip4_array,          &priv->wins },
+	const NMPropertiesInfo property_info[] = {
+		{ NM_IP4_CONFIG_ADDRESSES,    &priv->addresses, demarshal_ip4_address_array },
+		{ NM_IP4_CONFIG_NAMESERVERS,  &priv->nameservers, demarshal_ip4_array },
+		{ NM_IP4_CONFIG_DOMAINS,      &priv->domains, demarshal_domains },
+		{ NM_IP4_CONFIG_ROUTES,       &priv->routes, demarshal_ip4_routes_array },
+		{ NM_IP4_CONFIG_WINS_SERVERS, &priv->wins, demarshal_ip4_array },
 		{ NULL },
 	};
 
-	_nm_object_handle_properties_changed (NM_OBJECT (config),
-	                                     priv->proxy,
-	                                     property_changed_info);
+	_nm_object_register_properties (NM_OBJECT (config),
+	                                priv->proxy,
+	                                property_info);
 }
 
 static GObject*
@@ -155,7 +155,7 @@ constructor (GType type,
 										   nm_object_get_path (object),
 										   NM_DBUS_INTERFACE_IP4_CONFIG);
 
-	register_for_property_changed (NM_IP4_CONFIG (object));
+	register_properties (NM_IP4_CONFIG (object));
 
 	return G_OBJECT (object);
 }
diff --git a/libnm-glib/nm-ip6-config.c b/libnm-glib/nm-ip6-config.c
index 7e9bf3c..f62ab82 100644
--- a/libnm-glib/nm-ip6-config.c
+++ b/libnm-glib/nm-ip6-config.c
@@ -124,20 +124,20 @@ demarshal_ip6_routes_array (NMObject *object, GParamSpec *pspec, GValue *value,
 }
 
 static void
-register_for_property_changed (NMIP6Config *config)
+register_properties (NMIP6Config *config)
 {
 	NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config);
-	const NMPropertiesChangedInfo property_changed_info[] = {
-		{ NM_IP6_CONFIG_ADDRESSES,    demarshal_ip6_address_array,    &priv->addresses },
-		{ NM_IP6_CONFIG_NAMESERVERS,  demarshal_ip6_nameserver_array, &priv->nameservers },
-		{ NM_IP6_CONFIG_DOMAINS,      demarshal_domains,              &priv->domains },
-		{ NM_IP6_CONFIG_ROUTES,       demarshal_ip6_routes_array,     &priv->routes },
+	const NMPropertiesInfo property_info[] = {
+		{ NM_IP6_CONFIG_ADDRESSES,    &priv->addresses, demarshal_ip6_address_array },
+		{ NM_IP6_CONFIG_NAMESERVERS,  &priv->nameservers, demarshal_ip6_nameserver_array },
+		{ NM_IP6_CONFIG_DOMAINS,      &priv->domains, demarshal_domains },
+		{ NM_IP6_CONFIG_ROUTES,       &priv->routes, demarshal_ip6_routes_array },
 		{ NULL },
 	};
 
-	_nm_object_handle_properties_changed (NM_OBJECT (config),
-	                                      priv->proxy,
-	                                      property_changed_info);
+	_nm_object_register_properties (NM_OBJECT (config),
+	                                priv->proxy,
+	                                property_info);
 }
 
 /**
@@ -309,7 +309,7 @@ constructor (GType type,
 	                                         nm_object_get_path (NM_OBJECT (object)),
 	                                         NM_DBUS_INTERFACE_IP6_CONFIG);
 
-	register_for_property_changed (NM_IP6_CONFIG (object));
+	register_properties (NM_IP6_CONFIG (object));
 
 	return object;
 }
diff --git a/libnm-glib/nm-object-private.h b/libnm-glib/nm-object-private.h
index 4410df2..c01507d 100644
--- a/libnm-glib/nm-object-private.h
+++ b/libnm-glib/nm-object-private.h
@@ -27,24 +27,22 @@
 #include <glib-object.h>
 #include "nm-object.h"
 
-typedef gboolean (*PropChangedMarshalFunc) (NMObject *, GParamSpec *, GValue *, gpointer);
+typedef gboolean (*PropertyMarshalFunc) (NMObject *, GParamSpec *, GValue *, gpointer);
 typedef GObject * (*NMObjectCreatorFunc) (DBusGConnection *, const char *);
 
 typedef struct {
 	const char *name;
-	PropChangedMarshalFunc func;
 	gpointer field;
-} NMPropertiesChangedInfo;
+	PropertyMarshalFunc func;
+} NMPropertiesInfo;
 
 
-void _nm_object_handle_properties_changed (NMObject *object,
-                                           DBusGProxy *proxy,
-                                           const NMPropertiesChangedInfo *info);
+void _nm_object_register_properties (NMObject *object,
+									 DBusGProxy *proxy,
+									 const NMPropertiesInfo *info);
 
 void _nm_object_process_properties_changed (NMObject *self, GHashTable *properties);
 
-gboolean _nm_object_demarshal_generic (NMObject *object, GParamSpec *pspec, GValue *value, gpointer field);
-
 void _nm_object_queue_notify (NMObject *object, const char *property);
 
 /* DBus property accessors */
diff --git a/libnm-glib/nm-object.c b/libnm-glib/nm-object.c
index 9a8a60f..e606650 100644
--- a/libnm-glib/nm-object.c
+++ b/libnm-glib/nm-object.c
@@ -22,6 +22,7 @@
  */
 
 #include <string.h>
+#include <gio/gio.h>
 #include <nm-utils.h>
 #include "NetworkManager.h"
 #include "nm-object.h"
@@ -37,15 +38,16 @@ 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))
 
 typedef struct {
-	PropChangedMarshalFunc func;
+	PropertyMarshalFunc func;
 	gpointer field;
-} PropChangedInfo;
+} PropertyInfo;
 
 typedef struct {
 	DBusGConnection *connection;
 	char *path;
 	DBusGProxy *properties_proxy;
-	GSList *pcs;
+	GSList *property_interfaces;
+	GSList *property_tables;
 	NMObject *parent;
 
 	GSList *notify_props;
@@ -118,6 +120,9 @@ dispose (GObject *object)
 	g_slist_foreach (priv->notify_props, (GFunc) g_free, NULL);
 	g_slist_free (priv->notify_props);
 
+	g_slist_foreach (priv->property_interfaces, (GFunc) g_free, NULL);
+	g_slist_free (priv->property_interfaces);
+
 	g_object_unref (priv->properties_proxy);
 	dbus_g_connection_unref (priv->connection);
 
@@ -129,8 +134,8 @@ finalize (GObject *object)
 {
 	NMObjectPrivate *priv = NM_OBJECT_GET_PRIVATE (object);
 
-	g_slist_foreach (priv->pcs, (GFunc) g_hash_table_destroy, NULL);
-	g_slist_free (priv->pcs);
+	g_slist_foreach (priv->property_tables, (GFunc) g_hash_table_destroy, NULL);
+	g_slist_free (priv->property_tables);
 	g_free (priv->path);
 
 	G_OBJECT_CLASS (nm_object_parent_class)->finalize (object);
@@ -334,37 +339,25 @@ handle_property_changed (gpointer key, gpointer data, gpointer user_data)
 	NMObject *self = NM_OBJECT (user_data);
 	NMObjectPrivate *priv = NM_OBJECT_GET_PRIVATE (self);
 	char *prop_name;
-	PropChangedInfo *pci;
+	PropertyInfo *pi;
 	GParamSpec *pspec;
 	gboolean success = FALSE, found = FALSE;
 	GSList *iter;
 	GValue *value = data;
 
 	prop_name = wincaps_to_dash ((char *) key);
-	pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (G_OBJECT (self)), prop_name);
-	if (!pspec) {
-		g_warning ("%s: property '%s' changed but wasn't defined by object type %s.",
-		           __func__,
-		           prop_name,
-		           G_OBJECT_TYPE_NAME (self));
-		goto out;
-	}
 
 	/* Iterate through the object and its parents to find the property */
-	for (iter = priv->pcs; iter; iter = g_slist_next (iter)) {
-		pci = g_hash_table_lookup ((GHashTable *) iter->data, prop_name);
-		if (pci) {
-			found = TRUE;
-
-			/* 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;
+	for (iter = priv->property_tables; iter; iter = g_slist_next (iter)) {
+		pi = g_hash_table_lookup ((GHashTable *) iter->data, prop_name);
+		if (pi) {
+			if (!pi->field) {
+				/* We know about this property but aren't tracking changes on it. */
+				goto out;
 			}
 
-			success = (*(pci->func)) (self, pspec, value, pci->field);
-			if (success)
-				break;
+			found = TRUE;
+			break;
 		}
 	}
 
@@ -372,7 +365,26 @@ handle_property_changed (gpointer key, gpointer data, gpointer user_data)
 #if DEBUG
 		g_warning ("Property '%s' unhandled.", prop_name);
 #endif
-	} else if (!success) {
+		goto out;
+	}
+
+	pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (G_OBJECT (self)), prop_name);
+	if (!pspec) {
+		g_warning ("%s: property '%s' changed but wasn't defined by object type %s.",
+		           __func__,
+		           prop_name,
+		           G_OBJECT_TYPE_NAME (self));
+		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;
+	}
+
+	success = (*(pi->func)) (self, pspec, value, pi->field);
+	if (!success) {
 		g_warning ("%s: failed to update property '%s' of object type %s.",
 		           __func__,
 		           prop_name,
@@ -397,48 +409,6 @@ properties_changed_proxy (DBusGProxy *proxy,
 	_nm_object_process_properties_changed (NM_OBJECT (user_data), properties);
 }
 
-void
-_nm_object_handle_properties_changed (NMObject *object,
-                                     DBusGProxy *proxy,
-                                     const NMPropertiesChangedInfo *info)
-{
-	NMObjectPrivate *priv = NM_OBJECT_GET_PRIVATE (object);
-	NMPropertiesChangedInfo *tmp;
-	GHashTable *instance;
-
-	g_return_if_fail (NM_IS_OBJECT (object));
-	g_return_if_fail (proxy != NULL);
-	g_return_if_fail (info != NULL);
-
-	dbus_g_proxy_add_signal (proxy, "PropertiesChanged", DBUS_TYPE_G_MAP_OF_VARIANT, G_TYPE_INVALID);
-	dbus_g_proxy_connect_signal (proxy,
-						    "PropertiesChanged",
-						    G_CALLBACK (properties_changed_proxy),
-						    object,
-						    NULL);
-
-	instance = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
-	priv->pcs = g_slist_prepend (priv->pcs, instance);
-
-	for (tmp = (NMPropertiesChangedInfo *) info; tmp->name; tmp++) {
-		PropChangedInfo *pci;
-
-		if (!tmp->name || !tmp->func || !tmp->field) {
-			g_warning ("%s: missing field in NMPropertiesChangedInfo", __func__);
-			continue;
-		}
-
-		pci = g_malloc0 (sizeof (PropChangedInfo));
-		if (!pci) {
-			g_warning ("%s: not enough memory for PropChangedInfo", __func__);
-			continue;
-		}
-		pci->func = tmp->func;
-		pci->field = tmp->field;
-		g_hash_table_insert (instance, g_strdup (tmp->name), pci);
-	}
-}
-
 #define HANDLE_TYPE(ucase, lcase, getter) \
 	} else if (pspec->value_type == G_TYPE_##ucase) { \
 		if (G_VALUE_HOLDS_##ucase (value)) { \
@@ -449,11 +419,11 @@ _nm_object_handle_properties_changed (NMObject *object,
 			goto done; \
 		}
 
-gboolean
-_nm_object_demarshal_generic (NMObject *object,
-                             GParamSpec *pspec,
-                             GValue *value,
-                             gpointer field)
+static gboolean
+demarshal_generic (NMObject *object,
+                   GParamSpec *pspec,
+                   GValue *value,
+                   gpointer field)
 {
 	gboolean success = TRUE;
 
@@ -503,6 +473,47 @@ done:
 	return success;
 }
 
+void
+_nm_object_register_properties (NMObject *object,
+                                DBusGProxy *proxy,
+                                const NMPropertiesInfo *info)
+{
+	NMObjectPrivate *priv = NM_OBJECT_GET_PRIVATE (object);
+	NMPropertiesInfo *tmp;
+	GHashTable *instance;
+
+	g_return_if_fail (NM_IS_OBJECT (object));
+	g_return_if_fail (proxy != NULL);
+	g_return_if_fail (info != NULL);
+
+	priv->property_interfaces = g_slist_prepend (priv->property_interfaces,
+	                                             g_strdup (dbus_g_proxy_get_interface (proxy)));
+
+	dbus_g_proxy_add_signal (proxy, "PropertiesChanged", DBUS_TYPE_G_MAP_OF_VARIANT, G_TYPE_INVALID);
+	dbus_g_proxy_connect_signal (proxy,
+						    "PropertiesChanged",
+						    G_CALLBACK (properties_changed_proxy),
+						    object,
+						    NULL);
+
+	instance = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
+	priv->property_tables = g_slist_prepend (priv->property_tables, instance);
+
+	for (tmp = (NMPropertiesInfo *) info; tmp->name; tmp++) {
+		PropertyInfo *pi;
+
+		if (!tmp->name || (tmp->func && !tmp->field)) {
+			g_warning ("%s: missing field in NMPropertiesInfo", __func__);
+			continue;
+		}
+
+		pi = g_malloc0 (sizeof (PropertyInfo));
+		pi->func = tmp->func ? tmp->func : demarshal_generic;
+		pi->field = tmp->field;
+		g_hash_table_insert (instance, g_strdup (tmp->name), pi);
+	}
+}
+
 gboolean
 _nm_object_get_property (NMObject *object,
                          const char *interface,
diff --git a/libnm-glib/nm-vpn-connection.c b/libnm-glib/nm-vpn-connection.c
index 2a83cae..94d4110 100644
--- a/libnm-glib/nm-vpn-connection.c
+++ b/libnm-glib/nm-vpn-connection.c
@@ -167,6 +167,21 @@ nm_vpn_connection_init (NMVPNConnection *connection)
 	priv->vpn_state = NM_VPN_CONNECTION_STATE_UNKNOWN;
 }
 
+static void
+register_properties (NMVPNConnection *connection)
+{
+	NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (connection);
+	const NMPropertiesInfo property_info[] = {
+		{ NM_VPN_CONNECTION_BANNER,    &priv->banner },
+		{ NM_VPN_CONNECTION_VPN_STATE, &priv->vpn_state },
+		{ NULL },
+	};
+
+	_nm_object_register_properties (NM_OBJECT (connection),
+	                                priv->proxy,
+	                                property_info);
+}
+
 static GObject*
 constructor (GType type,
 		   guint n_construct_params,
@@ -198,6 +213,9 @@ constructor (GType type,
 						    G_CALLBACK (vpn_state_changed_proxy),
 						    object,
 						    NULL);
+
+	register_properties (NM_VPN_CONNECTION (object));
+
 	return G_OBJECT (object);
 }
 
diff --git a/libnm-glib/nm-wimax-nsp.c b/libnm-glib/nm-wimax-nsp.c
index 2147849..a4f1ea8 100644
--- a/libnm-glib/nm-wimax-nsp.c
+++ b/libnm-glib/nm-wimax-nsp.c
@@ -290,17 +290,19 @@ get_property (GObject *object,
 }
 
 static void
-register_for_property_changed (NMWimaxNsp *nsp)
+register_properties (NMWimaxNsp *nsp)
 {
 	NMWimaxNspPrivate *priv = NM_WIMAX_NSP_GET_PRIVATE (nsp);
-	const NMPropertiesChangedInfo property_changed_info[] = {
-		{ NM_WIMAX_NSP_SIGNAL_QUALITY, _nm_object_demarshal_generic, &priv->signal_quality },
+	const NMPropertiesInfo property_info[] = {
+		{ NM_WIMAX_NSP_NAME,           &priv->name },
+		{ NM_WIMAX_NSP_SIGNAL_QUALITY, &priv->signal_quality },
+		{ NM_WIMAX_NSP_NETWORK_TYPE,   &priv->network_type },
 		{ NULL },
 	};
 
-	_nm_object_handle_properties_changed (NM_OBJECT (nsp),
-										  priv->proxy,
-										  property_changed_info);
+	_nm_object_register_properties (NM_OBJECT (nsp),
+	                                priv->proxy,
+	                                property_info);
 }
 
 static GObject*
@@ -324,7 +326,7 @@ constructor (GType type,
 											 nm_object_get_path (object),
 											 NM_DBUS_INTERFACE_WIMAX_NSP);
 
-	register_for_property_changed (NM_WIMAX_NSP (object));
+	register_properties (NM_WIMAX_NSP (object));
 
 	return G_OBJECT (object);
 }
-- 
1.7.7.5

>From 661e955a55def82741f1920aadf05e5a936b8f2a Mon Sep 17 00:00:00 2001
From: Dan Winship <danw gnome org>
Date: Thu, 19 Jan 2012 18:23:28 -0500
Subject: [PATCH 07/12] libnm-glib: simplify property getter methods

Rather than having every property getter method have code to fetch
that specific property's value, just call the new
_nm_object_ensure_inited() (which makes sure that we've read all the
property values on the object at least once), and then return the
cached value. (After we've read the initial property values, the
PropertiesChanged signal handler will ensure that the values are kept
up to date, so we can always just return cached property values after
that point.)

This then lets us get rid of _nm_object_get_property() and its
wrappers.
---
 libnm-glib/nm-access-point.c      |  117 +++---------------
 libnm-glib/nm-active-connection.c |  112 +++---------------
 libnm-glib/nm-client.c            |  166 +++++++++----------------
 libnm-glib/nm-device-bt.c         |   41 +------
 libnm-glib/nm-device-ethernet.c   |   55 ++-------
 libnm-glib/nm-device-infiniband.c |   29 +----
 libnm-glib/nm-device-modem.c      |   26 +----
 libnm-glib/nm-device-wifi.c       |   90 ++------------
 libnm-glib/nm-device-wimax.c      |   99 ++-------------
 libnm-glib/nm-device.c            |  245 ++++---------------------------------
 libnm-glib/nm-dhcp4-config.c      |   20 +---
 libnm-glib/nm-dhcp6-config.c      |   20 +---
 libnm-glib/nm-ip4-config.c        |  114 ++----------------
 libnm-glib/nm-ip6-config.c        |   86 ++------------
 libnm-glib/nm-object-private.h    |   52 +-------
 libnm-glib/nm-object.c            |  232 +++++++++--------------------------
 libnm-glib/nm-vpn-connection.c    |   24 +---
 libnm-glib/nm-wimax-nsp.c         |   38 +-----
 18 files changed, 264 insertions(+), 1302 deletions(-)

diff --git a/libnm-glib/nm-access-point.c b/libnm-glib/nm-access-point.c
index 2a5d20c..9a25365 100644
--- a/libnm-glib/nm-access-point.c
+++ b/libnm-glib/nm-access-point.c
@@ -113,19 +113,10 @@ nm_access_point_new (DBusGConnection *connection, const char *path)
 NM80211ApFlags
 nm_access_point_get_flags (NMAccessPoint *ap)
 {
-	NMAccessPointPrivate *priv;
-
 	g_return_val_if_fail (NM_IS_ACCESS_POINT (ap), NM_802_11_AP_FLAGS_NONE);
 
-	priv = NM_ACCESS_POINT_GET_PRIVATE (ap);
-	if (!priv->flags) {
-		priv->flags = _nm_object_get_uint_property (NM_OBJECT (ap),
-		                                           NM_DBUS_INTERFACE_ACCESS_POINT,
-		                                           DBUS_PROP_FLAGS,
-		                                           NULL);
-	}
-
-	return priv->flags;
+	_nm_object_ensure_inited (NM_OBJECT (ap));
+	return NM_ACCESS_POINT_GET_PRIVATE (ap)->flags;
 }
 
 /**
@@ -139,19 +130,10 @@ nm_access_point_get_flags (NMAccessPoint *ap)
 NM80211ApSecurityFlags
 nm_access_point_get_wpa_flags (NMAccessPoint *ap)
 {
-	NMAccessPointPrivate *priv;
-
 	g_return_val_if_fail (NM_IS_ACCESS_POINT (ap), NM_802_11_AP_SEC_NONE);
 
-	priv = NM_ACCESS_POINT_GET_PRIVATE (ap);
-	if (!priv->wpa_flags) {
-		priv->wpa_flags = _nm_object_get_uint_property (NM_OBJECT (ap),
-		                                               NM_DBUS_INTERFACE_ACCESS_POINT,
-		                                               DBUS_PROP_WPA_FLAGS,
-		                                               NULL);
-	}
-
-	return priv->wpa_flags;
+	_nm_object_ensure_inited (NM_OBJECT (ap));
+	return NM_ACCESS_POINT_GET_PRIVATE (ap)->wpa_flags;
 }
 
 /**
@@ -166,19 +148,10 @@ nm_access_point_get_wpa_flags (NMAccessPoint *ap)
 NM80211ApSecurityFlags
 nm_access_point_get_rsn_flags (NMAccessPoint *ap)
 {
-	NMAccessPointPrivate *priv;
-
 	g_return_val_if_fail (NM_IS_ACCESS_POINT (ap), NM_802_11_AP_SEC_NONE);
 
-	priv = NM_ACCESS_POINT_GET_PRIVATE (ap);
-	if (!priv->rsn_flags) {
-		priv->rsn_flags = _nm_object_get_uint_property (NM_OBJECT (ap),
-		                                               NM_DBUS_INTERFACE_ACCESS_POINT,
-		                                               DBUS_PROP_RSN_FLAGS,
-		                                               NULL);
-	}
-
-	return priv->rsn_flags;
+	_nm_object_ensure_inited (NM_OBJECT (ap));
+	return NM_ACCESS_POINT_GET_PRIVATE (ap)->rsn_flags;
 }
 
 /**
@@ -193,19 +166,10 @@ nm_access_point_get_rsn_flags (NMAccessPoint *ap)
 const GByteArray *
 nm_access_point_get_ssid (NMAccessPoint *ap)
 {
-	NMAccessPointPrivate *priv;
-
 	g_return_val_if_fail (NM_IS_ACCESS_POINT (ap), NULL);
 
-	priv = NM_ACCESS_POINT_GET_PRIVATE (ap);
-	if (!priv->ssid) {
-		priv->ssid = _nm_object_get_byte_array_property (NM_OBJECT (ap),
-		                                                NM_DBUS_INTERFACE_ACCESS_POINT,
-		                                                DBUS_PROP_SSID,
-		                                                NULL);
-	}
-
-	return priv->ssid;
+	_nm_object_ensure_inited (NM_OBJECT (ap));
+	return NM_ACCESS_POINT_GET_PRIVATE (ap)->ssid;
 }
 
 /**
@@ -219,19 +183,10 @@ nm_access_point_get_ssid (NMAccessPoint *ap)
 guint32
 nm_access_point_get_frequency (NMAccessPoint *ap)
 {
-	NMAccessPointPrivate *priv;
-
 	g_return_val_if_fail (NM_IS_ACCESS_POINT (ap), 0);
 
-	priv = NM_ACCESS_POINT_GET_PRIVATE (ap);
-	if (!priv->frequency) {
-		priv->frequency = _nm_object_get_uint_property (NM_OBJECT (ap),
-		                                               NM_DBUS_INTERFACE_ACCESS_POINT,
-		                                               DBUS_PROP_FREQUENCY,
-		                                               NULL);
-	}
-
-	return priv->frequency;
+	_nm_object_ensure_inited (NM_OBJECT (ap));
+	return NM_ACCESS_POINT_GET_PRIVATE (ap)->frequency;
 }
 
 /**
@@ -246,19 +201,10 @@ nm_access_point_get_frequency (NMAccessPoint *ap)
 const char *
 nm_access_point_get_bssid (NMAccessPoint *ap)
 {
-	NMAccessPointPrivate *priv;
-
 	g_return_val_if_fail (NM_IS_ACCESS_POINT (ap), NULL);
 
-	priv = NM_ACCESS_POINT_GET_PRIVATE (ap);
-	if (!priv->bssid) {
-		priv->bssid = _nm_object_get_string_property (NM_OBJECT (ap),
-		                                              NM_DBUS_INTERFACE_ACCESS_POINT,
-		                                              DBUS_PROP_HW_ADDRESS,
-		                                              NULL);
-	}
-
-	return priv->bssid;
+	_nm_object_ensure_inited (NM_OBJECT (ap));
+	return NM_ACCESS_POINT_GET_PRIVATE (ap)->bssid;
 }
 
 /**
@@ -289,19 +235,10 @@ nm_access_point_get_hw_address (NMAccessPoint *ap)
 NM80211Mode
 nm_access_point_get_mode (NMAccessPoint *ap)
 {
-	NMAccessPointPrivate *priv;
-
 	g_return_val_if_fail (NM_IS_ACCESS_POINT (ap), 0);
 
-	priv = NM_ACCESS_POINT_GET_PRIVATE (ap);
-	if (!priv->mode) {
-		priv->mode = _nm_object_get_uint_property (NM_OBJECT (ap),
-		                                          NM_DBUS_INTERFACE_ACCESS_POINT,
-		                                          DBUS_PROP_MODE,
-		                                          NULL);
-	}
-
-	return priv->mode;
+	_nm_object_ensure_inited (NM_OBJECT (ap));
+	return NM_ACCESS_POINT_GET_PRIVATE (ap)->mode;
 }
 
 /**
@@ -315,19 +252,10 @@ nm_access_point_get_mode (NMAccessPoint *ap)
 guint32
 nm_access_point_get_max_bitrate (NMAccessPoint *ap)
 {
-	NMAccessPointPrivate *priv;
-
 	g_return_val_if_fail (NM_IS_ACCESS_POINT (ap), 0);
 
-	priv = NM_ACCESS_POINT_GET_PRIVATE (ap);
-	if (!priv->max_bitrate) {
-		priv->max_bitrate = _nm_object_get_uint_property (NM_OBJECT (ap),
-		                                              NM_DBUS_INTERFACE_ACCESS_POINT,
-		                                              DBUS_PROP_MAX_BITRATE,
-		                                              NULL);
-	}
-
-	return priv->max_bitrate;
+	_nm_object_ensure_inited (NM_OBJECT (ap));
+	return NM_ACCESS_POINT_GET_PRIVATE (ap)->max_bitrate;
 }
 
 /**
@@ -341,19 +269,10 @@ nm_access_point_get_max_bitrate (NMAccessPoint *ap)
 guint8
 nm_access_point_get_strength (NMAccessPoint *ap)
 {
-	NMAccessPointPrivate *priv;
-
 	g_return_val_if_fail (NM_IS_ACCESS_POINT (ap), 0);
 
-	priv = NM_ACCESS_POINT_GET_PRIVATE (ap);
-	if (!priv->strength) {
-		priv->strength = _nm_object_get_byte_property (NM_OBJECT (ap),
-		                                              NM_DBUS_INTERFACE_ACCESS_POINT,
-		                                              DBUS_PROP_STRENGTH,
-		                                              NULL);
-	}
-
-	return priv->strength;
+	_nm_object_ensure_inited (NM_OBJECT (ap));
+	return NM_ACCESS_POINT_GET_PRIVATE (ap)->strength;
 }
 
 /**
diff --git a/libnm-glib/nm-active-connection.c b/libnm-glib/nm-active-connection.c
index 2c37e71..a68da56 100644
--- a/libnm-glib/nm-active-connection.c
+++ b/libnm-glib/nm-active-connection.c
@@ -107,19 +107,10 @@ nm_active_connection_new (DBusGConnection *connection, const char *path)
 const char *
 nm_active_connection_get_connection (NMActiveConnection *connection)
 {
-	NMActiveConnectionPrivate *priv;
-
 	g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (connection), NULL);
 
-	priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (connection);
-	if (!priv->connection) {
-		priv->connection = _nm_object_get_string_property (NM_OBJECT (connection),
-		                                                  NM_DBUS_INTERFACE_ACTIVE_CONNECTION,
-		                                                  DBUS_PROP_CONNECTION,
-		                                                  NULL);
-	}
-
-	return priv->connection;
+	_nm_object_ensure_inited (NM_OBJECT (connection));
+	return NM_ACTIVE_CONNECTION_GET_PRIVATE (connection)->connection;
 }
 
 /**
@@ -134,19 +125,10 @@ nm_active_connection_get_connection (NMActiveConnection *connection)
 const char *
 nm_active_connection_get_uuid (NMActiveConnection *connection)
 {
-	NMActiveConnectionPrivate *priv;
-
 	g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (connection), NULL);
 
-	priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (connection);
-	if (!priv->uuid) {
-		priv->uuid = _nm_object_get_string_property (NM_OBJECT (connection),
-		                                             NM_DBUS_INTERFACE_ACTIVE_CONNECTION,
-		                                             DBUS_PROP_UUID,
-		                                             NULL);
-	}
-
-	return priv->uuid;
+	_nm_object_ensure_inited (NM_OBJECT (connection));
+	return NM_ACTIVE_CONNECTION_GET_PRIVATE (connection)->uuid;
 }
 
 /**
@@ -161,19 +143,10 @@ nm_active_connection_get_uuid (NMActiveConnection *connection)
 const char *
 nm_active_connection_get_specific_object (NMActiveConnection *connection)
 {
-	NMActiveConnectionPrivate *priv;
-
 	g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (connection), NULL);
 
-	priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (connection);
-	if (!priv->specific_object) {
-		priv->specific_object = _nm_object_get_string_property (NM_OBJECT (connection),
-		                                                       NM_DBUS_INTERFACE_ACTIVE_CONNECTION,
-		                                                       DBUS_PROP_SPECIFIC_OBJECT,
-		                                                       NULL);
-	}
-
-	return priv->specific_object;
+	_nm_object_ensure_inited (NM_OBJECT (connection));
+	return NM_ACTIVE_CONNECTION_GET_PRIVATE (connection)->specific_object;
 }
 
 /**
@@ -188,27 +161,10 @@ nm_active_connection_get_specific_object (NMActiveConnection *connection)
 const GPtrArray *
 nm_active_connection_get_devices (NMActiveConnection *connection)
 {
-	NMActiveConnectionPrivate *priv;
-	GValue value = { 0, };
-
 	g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (connection), NULL);
 
-	priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (connection);
-	if (priv->devices)
-		return handle_ptr_array_return (priv->devices);
-
-	if (!_nm_object_get_property (NM_OBJECT (connection),
-	                             NM_DBUS_INTERFACE_ACTIVE_CONNECTION,
-	                             DBUS_PROP_DEVICES,
-	                             &value,
-	                             NULL)) {
-		return NULL;
-	}
-
-	demarshal_devices (NM_OBJECT (connection), NULL, &value, &priv->devices);
-	g_value_unset (&value);
-
-	return handle_ptr_array_return (priv->devices);
+	_nm_object_ensure_inited (NM_OBJECT (connection));
+	return handle_ptr_array_return (NM_ACTIVE_CONNECTION_GET_PRIVATE (connection)->devices);
 }
 
 /**
@@ -222,19 +178,10 @@ nm_active_connection_get_devices (NMActiveConnection *connection)
 NMActiveConnectionState
 nm_active_connection_get_state (NMActiveConnection *connection)
 {
-	NMActiveConnectionPrivate *priv;
-
 	g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (connection), NM_ACTIVE_CONNECTION_STATE_UNKNOWN);
 
-	priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (connection);
-	if (!priv->state) {
-		priv->state = _nm_object_get_uint_property (NM_OBJECT (connection),
-		                                           NM_DBUS_INTERFACE_ACTIVE_CONNECTION,
-		                                           DBUS_PROP_STATE,
-		                                           NULL);
-	}
-
-	return priv->state;
+	_nm_object_ensure_inited (NM_OBJECT (connection));
+	return NM_ACTIVE_CONNECTION_GET_PRIVATE (connection)->state;
 }
 
 /**
@@ -249,19 +196,10 @@ nm_active_connection_get_state (NMActiveConnection *connection)
 gboolean
 nm_active_connection_get_default (NMActiveConnection *connection)
 {
-	NMActiveConnectionPrivate *priv;
-
 	g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (connection), FALSE);
 
-	priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (connection);
-	if (!priv->is_default) {
-		priv->is_default = _nm_object_get_boolean_property (NM_OBJECT (connection),
-		                                                    NM_DBUS_INTERFACE_ACTIVE_CONNECTION,
-		                                                    DBUS_PROP_DEFAULT,
-		                                                    NULL);
-	}
-
-	return priv->is_default;
+	_nm_object_ensure_inited (NM_OBJECT (connection));
+	return NM_ACTIVE_CONNECTION_GET_PRIVATE (connection)->is_default;
 }
 
 /**
@@ -276,19 +214,10 @@ nm_active_connection_get_default (NMActiveConnection *connection)
 gboolean
 nm_active_connection_get_default6 (NMActiveConnection *connection)
 {
-	NMActiveConnectionPrivate *priv;
-
 	g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (connection), FALSE);
 
-	priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (connection);
-	if (!priv->is_default6) {
-		priv->is_default6 = _nm_object_get_boolean_property (NM_OBJECT (connection),
-		                                                     NM_DBUS_INTERFACE_ACTIVE_CONNECTION,
-		                                                     DBUS_PROP_DEFAULT6,
-		                                                     NULL);
-	}
-
-	return priv->is_default6;
+	_nm_object_ensure_inited (NM_OBJECT (connection));
+	return NM_ACTIVE_CONNECTION_GET_PRIVATE (connection)->is_default6;
 }
 
 /**
@@ -303,19 +232,10 @@ nm_active_connection_get_default6 (NMActiveConnection *connection)
 const char *
 nm_active_connection_get_master (NMActiveConnection *connection)
 {
-	NMActiveConnectionPrivate *priv;
-
 	g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (connection), NULL);
 
-	priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (connection);
-	if (!priv->master) {
-		priv->master = _nm_object_get_string_property (NM_OBJECT (connection),
-		                                               NM_DBUS_INTERFACE_ACTIVE_CONNECTION,
-		                                               DBUS_PROP_MASTER,
-		                                               NULL);
-	}
-
-	return priv->master;
+	_nm_object_ensure_inited (NM_OBJECT (connection));
+	return NM_ACTIVE_CONNECTION_GET_PRIVATE (connection)->master;
 }
 
 static void
diff --git a/libnm-glib/nm-client.c b/libnm-glib/nm-client.c
index 42517c8..b46e0df 100644
--- a/libnm-glib/nm-client.c
+++ b/libnm-glib/nm-client.c
@@ -62,7 +62,6 @@ typedef struct {
 	 */
 	GSList *pending_activations;
 
-	gboolean have_networking_enabled;
 	gboolean networking_enabled;
 	gboolean wireless_enabled;
 	gboolean wireless_hw_enabled;
@@ -111,18 +110,6 @@ static void client_device_added_proxy (DBusGProxy *proxy, char *path, gpointer u
 static void client_device_removed_proxy (DBusGProxy *proxy, char *path, gpointer user_data);
 
 static void
-handle_net_enabled_changed (GObject *object,
-                            GParamSpec *pspec,
-                            GValue *value,
-                            gpointer user_data)
-{
-	NMClientPrivate *priv = NM_CLIENT_GET_PRIVATE (object);
-
-	/* Update the cache flag when it changes */
-	priv->have_networking_enabled = TRUE;
-}
-
-static void
 nm_client_init (NMClient *client)
 {
 	NMClientPrivate *priv = NM_CLIENT_GET_PRIVATE (client);
@@ -130,11 +117,6 @@ nm_client_init (NMClient *client)
 	priv->state = NM_STATE_UNKNOWN;
 
 	priv->permissions = g_hash_table_new (g_direct_hash, g_direct_equal);
-
-	g_signal_connect (client,
-	                  "notify::" NM_CLIENT_NETWORKING_ENABLED,
-	                  G_CALLBACK (handle_net_enabled_changed),
-	                  client);
 }
 
 static void
@@ -155,29 +137,29 @@ static void
 update_wireless_status (NMClient *client, gboolean notify)
 {
 	NMClientPrivate *priv = NM_CLIENT_GET_PRIVATE (client);
-	gboolean val;
+	gboolean oldval;
 	gboolean poke = FALSE;
 
-	val = _nm_object_get_boolean_property (NM_OBJECT (client),
-	                                       NM_DBUS_INTERFACE,
-	                                       "WirelessHardwareEnabled",
-	                                       NULL);
-	if (val != priv->wireless_hw_enabled) {
-		priv->wireless_hw_enabled = val;
+	oldval = priv->wireless_hw_enabled;
+	_nm_object_reload_property (NM_OBJECT (client),
+	                            NM_DBUS_INTERFACE,
+	                            "WirelessHardwareEnabled");
+	if (oldval != priv->wireless_hw_enabled) {
 		poke = TRUE;
 		if (notify)
 			_nm_object_queue_notify (NM_OBJECT (client), NM_CLIENT_WIRELESS_HARDWARE_ENABLED);
 	}
 
-	if (priv->wireless_hw_enabled == FALSE)
-		val = FALSE;
-	else
-		val = _nm_object_get_boolean_property (NM_OBJECT (client),
-		                                       NM_DBUS_INTERFACE,
-		                                       "WirelessEnabled",
-		                                       NULL);
-	if (val != priv->wireless_enabled) {
-		priv->wireless_enabled = val;
+	oldval = priv->wireless_enabled;
+	if (priv->wireless_hw_enabled == FALSE) {
+		priv->wireless_enabled = FALSE;
+	} else {
+		_nm_object_reload_property (NM_OBJECT (client),
+		                            NM_DBUS_INTERFACE,
+		                            "WirelessEnabled");
+	}
+
+	if (oldval != priv->wireless_enabled) {
 		poke = TRUE;
 		if (notify)
 			_nm_object_queue_notify (NM_OBJECT (client), NM_CLIENT_WIRELESS_ENABLED);
@@ -197,29 +179,27 @@ static void
 update_wwan_status (NMClient *client, gboolean notify)
 {
 	NMClientPrivate *priv = NM_CLIENT_GET_PRIVATE (client);
-	gboolean val;
-
-	val = _nm_object_get_boolean_property (NM_OBJECT (client),
-	                                       NM_DBUS_INTERFACE,
-	                                       "WwanHardwareEnabled",
-	                                       NULL);
-	if (val != priv->wwan_hw_enabled) {
-		priv->wwan_hw_enabled = val;
+	gboolean oldval;
+
+	oldval = priv->wwan_hw_enabled;
+	_nm_object_reload_property (NM_OBJECT (client),
+	                            NM_DBUS_INTERFACE,
+	                            "WwanHardwareEnabled");
+	if (oldval != priv->wwan_hw_enabled) {
 		if (notify)
 			_nm_object_queue_notify (NM_OBJECT (client), NM_CLIENT_WWAN_HARDWARE_ENABLED);
 	}
 
-	if (priv->wwan_hw_enabled == FALSE)
-		val = FALSE;
-	else {
-		val = _nm_object_get_boolean_property (NM_OBJECT (client),
-		                                       NM_DBUS_INTERFACE,
-		                                       "WwanEnabled",
-		                                       NULL);
+	oldval = priv->wwan_enabled;
+	if (priv->wwan_hw_enabled == FALSE) {
+		priv->wwan_enabled = FALSE;
+	} else {
+		_nm_object_reload_property (NM_OBJECT (client),
+		                            NM_DBUS_INTERFACE,
+		                            "WwanEnabled");
 	}
 
-	if (val != priv->wwan_enabled) {
-		priv->wwan_enabled = val;
+	if (oldval != priv->wwan_enabled) {
 		if (notify)
 			_nm_object_queue_notify (NM_OBJECT (client), NM_CLIENT_WWAN_ENABLED);
 	}
@@ -229,29 +209,27 @@ static void
 update_wimax_status (NMClient *client, gboolean notify)
 {
 	NMClientPrivate *priv = NM_CLIENT_GET_PRIVATE (client);
-	gboolean val;
-
-	val = _nm_object_get_boolean_property (NM_OBJECT (client),
-	                                       NM_DBUS_INTERFACE,
-	                                       "WimaxHardwareEnabled",
-	                                       NULL);
-	if (val != priv->wimax_hw_enabled) {
-		priv->wimax_hw_enabled = val;
+	gboolean oldval;
+
+	oldval = priv->wimax_hw_enabled;
+	_nm_object_reload_property (NM_OBJECT (client),
+	                            NM_DBUS_INTERFACE,
+	                            "WimaxHardwareEnabled");
+	if (oldval != priv->wimax_hw_enabled) {
 		if (notify)
 			_nm_object_queue_notify (NM_OBJECT (client), NM_CLIENT_WIMAX_HARDWARE_ENABLED);
 	}
 
-	if (priv->wimax_hw_enabled == FALSE)
-		val = FALSE;
-	else {
-		val = _nm_object_get_boolean_property (NM_OBJECT (client),
-		                                       NM_DBUS_INTERFACE,
-		                                       "WimaxEnabled",
-		                                       NULL);
+	oldval = priv->wimax_enabled;
+	if (priv->wimax_hw_enabled == FALSE) {
+		priv->wimax_enabled = FALSE;
+	} else {
+		_nm_object_reload_property (NM_OBJECT (client),
+		                            NM_DBUS_INTERFACE,
+		                            "WimaxEnabled");
 	}
 
-	if (val != priv->wimax_enabled) {
-		priv->wimax_enabled = val;
+	if (oldval != priv->wimax_enabled) {
 		if (notify)
 			_nm_object_queue_notify (NM_OBJECT (client), NM_CLIENT_WIMAX_ENABLED);
 	}
@@ -877,28 +855,14 @@ const GPtrArray *
 nm_client_get_active_connections (NMClient *client)
 {
 	NMClientPrivate *priv;
-	GValue value = { 0, };
 
 	g_return_val_if_fail (NM_IS_CLIENT (client), NULL);
 
 	priv = NM_CLIENT_GET_PRIVATE (client);
-	if (priv->active_connections)
-		return handle_ptr_array_return (priv->active_connections);
-
 	if (!priv->manager_running)
 		return NULL;
 
-	if (!_nm_object_get_property (NM_OBJECT (client),
-	                             "org.freedesktop.NetworkManager",
-	                             "ActiveConnections",
-	                             &value,
-	                             NULL)) {
-		return NULL;
-	}
-
-	demarshal_active_connections (NM_OBJECT (client), NULL, &value, &priv->active_connections);
-	g_value_unset (&value);
-
+	_nm_object_ensure_inited (NM_OBJECT (client));
 	return handle_ptr_array_return (priv->active_connections);
 }
 
@@ -915,6 +879,7 @@ nm_client_wireless_get_enabled (NMClient *client)
 {
 	g_return_val_if_fail (NM_IS_CLIENT (client), FALSE);
 
+	_nm_object_ensure_inited (NM_OBJECT (client));
 	return NM_CLIENT_GET_PRIVATE (client)->wireless_enabled;
 }
 
@@ -954,6 +919,7 @@ nm_client_wireless_hardware_get_enabled (NMClient *client)
 {
 	g_return_val_if_fail (NM_IS_CLIENT (client), FALSE);
 
+	_nm_object_ensure_inited (NM_OBJECT (client));
 	return NM_CLIENT_GET_PRIVATE (client)->wireless_hw_enabled;
 }
 
@@ -970,6 +936,7 @@ nm_client_wwan_get_enabled (NMClient *client)
 {
 	g_return_val_if_fail (NM_IS_CLIENT (client), FALSE);
 
+	_nm_object_ensure_inited (NM_OBJECT (client));
 	return NM_CLIENT_GET_PRIVATE (client)->wwan_enabled;
 }
 
@@ -1009,6 +976,7 @@ nm_client_wwan_hardware_get_enabled (NMClient *client)
 {
 	g_return_val_if_fail (NM_IS_CLIENT (client), FALSE);
 
+	_nm_object_ensure_inited (NM_OBJECT (client));
 	return NM_CLIENT_GET_PRIVATE (client)->wwan_hw_enabled;
 }
 
@@ -1025,6 +993,7 @@ nm_client_wimax_get_enabled (NMClient *client)
 {
 	g_return_val_if_fail (NM_IS_CLIENT (client), FALSE);
 
+	_nm_object_ensure_inited (NM_OBJECT (client));
 	return NM_CLIENT_GET_PRIVATE (client)->wimax_enabled;
 }
 
@@ -1064,6 +1033,7 @@ nm_client_wimax_hardware_get_enabled (NMClient *client)
 {
 	g_return_val_if_fail (NM_IS_CLIENT (client), FALSE);
 
+	_nm_object_ensure_inited (NM_OBJECT (client));
 	return NM_CLIENT_GET_PRIVATE (client)->wimax_hw_enabled;
 }
 
@@ -1079,7 +1049,6 @@ const char *
 nm_client_get_version (NMClient *client)
 {
 	NMClientPrivate *priv;
-	GError *err = NULL;
 
 	g_return_val_if_fail (NM_IS_CLIENT (client), NULL);
 
@@ -1088,13 +1057,7 @@ nm_client_get_version (NMClient *client)
 	if (!priv->manager_running)
 		return NULL;
 
-	if (!priv->version)
-		priv->version = _nm_object_get_string_property (NM_OBJECT (client), NM_DBUS_INTERFACE, "Version", &err);
-
-	/* TODO: we don't pass the error to the caller yet, maybe later */
-	if (err)
-		g_error_free (err);
-
+	_nm_object_ensure_inited (NM_OBJECT (client));
 	return priv->version;
 }
 
@@ -1118,9 +1081,7 @@ nm_client_get_state (NMClient *client)
 	if (!priv->manager_running)
 		return NM_STATE_UNKNOWN;
 
-	if (priv->state == NM_STATE_UNKNOWN)
-		priv->state = _nm_object_get_uint_property (NM_OBJECT (client), NM_DBUS_INTERFACE, "State", NULL);
-
+	_nm_object_ensure_inited (NM_OBJECT (client));
 	return priv->state;
 }
 
@@ -1135,23 +1096,10 @@ nm_client_get_state (NMClient *client)
 gboolean
 nm_client_networking_get_enabled (NMClient *client)
 {
-	NMClientPrivate *priv;
-
 	g_return_val_if_fail (NM_IS_CLIENT (client), FALSE);
 
-	priv = NM_CLIENT_GET_PRIVATE (client);
-	if (!priv->have_networking_enabled) {
-		priv = NM_CLIENT_GET_PRIVATE (client);
-		if (!priv->networking_enabled) {
-			priv->networking_enabled = _nm_object_get_boolean_property (NM_OBJECT (client),
-			                                                            NM_DBUS_INTERFACE,
-			                                                            "NetworkingEnabled",
-			                                                            NULL);
-			priv->have_networking_enabled = TRUE;
-		}
-	}
-
-	return priv->networking_enabled;
+	_nm_object_ensure_inited (NM_OBJECT (client));
+	return NM_CLIENT_GET_PRIVATE (client)->networking_enabled;
 }
 
 /**
diff --git a/libnm-glib/nm-device-bt.c b/libnm-glib/nm-device-bt.c
index 960f8ce..4c9f955 100644
--- a/libnm-glib/nm-device-bt.c
+++ b/libnm-glib/nm-device-bt.c
@@ -42,7 +42,6 @@ typedef struct {
 	char *hw_address;
 	char *name;
 	guint32 bt_capabilities;
-	gboolean bt_capabilities_valid;
 
 	gboolean disposed;
 } NMDeviceBtPrivate;
@@ -93,19 +92,10 @@ nm_device_bt_new (DBusGConnection *connection, const char *path)
 const char *
 nm_device_bt_get_hw_address (NMDeviceBt *device)
 {
-	NMDeviceBtPrivate *priv;
-
 	g_return_val_if_fail (NM_IS_DEVICE_BT (device), NULL);
 
-	priv = NM_DEVICE_BT_GET_PRIVATE (device);
-	if (!priv->hw_address) {
-		priv->hw_address = _nm_object_get_string_property (NM_OBJECT (device),
-		                                                   NM_DBUS_INTERFACE_DEVICE_BLUETOOTH,
-		                                                   DBUS_PROP_HW_ADDRESS,
-		                                                   NULL);
-	}
-
-	return priv->hw_address;
+	_nm_object_ensure_inited (NM_OBJECT (device));
+	return NM_DEVICE_BT_GET_PRIVATE (device)->hw_address;
 }
 
 /**
@@ -119,19 +109,10 @@ nm_device_bt_get_hw_address (NMDeviceBt *device)
 const char *
 nm_device_bt_get_name (NMDeviceBt *device)
 {
-	NMDeviceBtPrivate *priv;
-
 	g_return_val_if_fail (NM_IS_DEVICE_BT (device), NULL);
 
-	priv = NM_DEVICE_BT_GET_PRIVATE (device);
-	if (!priv->name) {
-		priv->name = _nm_object_get_string_property (NM_OBJECT (device),
-		                                             NM_DBUS_INTERFACE_DEVICE_BLUETOOTH,
-		                                             DBUS_PROP_NAME,
-		                                             NULL);
-	}
-
-	return priv->name;
+	_nm_object_ensure_inited (NM_OBJECT (device));
+	return NM_DEVICE_BT_GET_PRIVATE (device)->name;
 }
 
 /**
@@ -145,20 +126,10 @@ nm_device_bt_get_name (NMDeviceBt *device)
 NMBluetoothCapabilities
 nm_device_bt_get_capabilities (NMDeviceBt *device)
 {
-	NMDeviceBtPrivate *priv;
-
 	g_return_val_if_fail (NM_IS_DEVICE_BT (device), NM_BT_CAPABILITY_NONE);
 
-	priv = NM_DEVICE_BT_GET_PRIVATE (device);
-	if (!priv->bt_capabilities_valid) {
-		priv->bt_capabilities = _nm_object_get_uint_property (NM_OBJECT (device),
-		                                                      NM_DBUS_INTERFACE_DEVICE_BLUETOOTH,
-		                                                      DBUS_PROP_BT_CAPABILITIES,
-		                                                      NULL);
-		priv->bt_capabilities_valid = TRUE;
-	}
-
-	return priv->bt_capabilities;
+	_nm_object_ensure_inited (NM_OBJECT (device));
+	return NM_DEVICE_BT_GET_PRIVATE (device)->bt_capabilities;
 }
 
 static NMBluetoothCapabilities
diff --git a/libnm-glib/nm-device-ethernet.c b/libnm-glib/nm-device-ethernet.c
index 1eb8189..c043113 100644
--- a/libnm-glib/nm-device-ethernet.c
+++ b/libnm-glib/nm-device-ethernet.c
@@ -44,7 +44,6 @@ typedef struct {
 	char *perm_hw_address;
 	guint32 speed;
 	gboolean carrier;
-	gboolean carrier_valid;
 
 	gboolean disposed;
 } NMDeviceEthernetPrivate;
@@ -97,19 +96,10 @@ nm_device_ethernet_new (DBusGConnection *connection, const char *path)
 const char *
 nm_device_ethernet_get_hw_address (NMDeviceEthernet *device)
 {
-	NMDeviceEthernetPrivate *priv;
-
 	g_return_val_if_fail (NM_IS_DEVICE_ETHERNET (device), NULL);
 
-	priv = NM_DEVICE_ETHERNET_GET_PRIVATE (device);
-	if (!priv->hw_address) {
-		priv->hw_address = _nm_object_get_string_property (NM_OBJECT (device),
-		                                                  NM_DBUS_INTERFACE_DEVICE_WIRED,
-		                                                  DBUS_PROP_HW_ADDRESS,
-		                                                  NULL);
-	}
-
-	return priv->hw_address;
+	_nm_object_ensure_inited (NM_OBJECT (device));
+	return NM_DEVICE_ETHERNET_GET_PRIVATE (device)->hw_address;
 }
 
 /**
@@ -124,19 +114,10 @@ nm_device_ethernet_get_hw_address (NMDeviceEthernet *device)
 const char *
 nm_device_ethernet_get_permanent_hw_address (NMDeviceEthernet *device)
 {
-	NMDeviceEthernetPrivate *priv;
-
 	g_return_val_if_fail (NM_IS_DEVICE_ETHERNET (device), NULL);
 
-	priv = NM_DEVICE_ETHERNET_GET_PRIVATE (device);
-	if (!priv->perm_hw_address) {
-		priv->perm_hw_address = _nm_object_get_string_property (NM_OBJECT (device),
-		                                                        NM_DBUS_INTERFACE_DEVICE_WIRED,
-		                                                        DBUS_PROP_PERM_HW_ADDRESS,
-		                                                        NULL);
-	}
-
-	return priv->perm_hw_address;
+	_nm_object_ensure_inited (NM_OBJECT (device));
+	return NM_DEVICE_ETHERNET_GET_PRIVATE (device)->perm_hw_address;
 }
 
 /**
@@ -150,19 +131,10 @@ nm_device_ethernet_get_permanent_hw_address (NMDeviceEthernet *device)
 guint32
 nm_device_ethernet_get_speed (NMDeviceEthernet *device)
 {
-	NMDeviceEthernetPrivate *priv;
-
 	g_return_val_if_fail (NM_IS_DEVICE_ETHERNET (device), 0);
 
-	priv = NM_DEVICE_ETHERNET_GET_PRIVATE (device);
-	if (!priv->speed) {
-		priv->speed = _nm_object_get_uint_property (NM_OBJECT (device),
-		                                           NM_DBUS_INTERFACE_DEVICE_WIRED,
-		                                           DBUS_PROP_SPEED,
-		                                           NULL);
-	}
-
-	return priv->speed;
+	_nm_object_ensure_inited (NM_OBJECT (device));
+	return NM_DEVICE_ETHERNET_GET_PRIVATE (device)->speed;
 }
 
 /**
@@ -176,20 +148,10 @@ nm_device_ethernet_get_speed (NMDeviceEthernet *device)
 gboolean
 nm_device_ethernet_get_carrier (NMDeviceEthernet *device)
 {
-	NMDeviceEthernetPrivate *priv;
-
 	g_return_val_if_fail (NM_IS_DEVICE_ETHERNET (device), FALSE);
 
-	priv = NM_DEVICE_ETHERNET_GET_PRIVATE (device);
-	if (!priv->carrier_valid) {
-		priv->carrier = _nm_object_get_boolean_property (NM_OBJECT (device),
-		                                                NM_DBUS_INTERFACE_DEVICE_WIRED,
-		                                                DBUS_PROP_CARRIER,
-		                                                NULL);
-		priv->carrier_valid = TRUE;
-	}
-
-	return priv->carrier;
+	_nm_object_ensure_inited (NM_OBJECT (device));
+	return NM_DEVICE_ETHERNET_GET_PRIVATE (device)->carrier;
 }
 
 static gboolean
@@ -243,7 +205,6 @@ nm_device_ethernet_init (NMDeviceEthernet *device)
 
 	priv->disposed = FALSE;
 	priv->carrier = FALSE;
-	priv->carrier_valid = FALSE;
 }
 
 static void
diff --git a/libnm-glib/nm-device-infiniband.c b/libnm-glib/nm-device-infiniband.c
index 576f7ee..384a348 100644
--- a/libnm-glib/nm-device-infiniband.c
+++ b/libnm-glib/nm-device-infiniband.c
@@ -43,7 +43,6 @@ typedef struct {
 
 	char *hw_address;
 	gboolean carrier;
-	gboolean carrier_valid;
 } NMDeviceInfinibandPrivate;
 
 enum {
@@ -90,19 +89,10 @@ nm_device_infiniband_new (DBusGConnection *connection, const char *path)
 const char *
 nm_device_infiniband_get_hw_address (NMDeviceInfiniband *device)
 {
-	NMDeviceInfinibandPrivate *priv;
-
 	g_return_val_if_fail (NM_IS_DEVICE_INFINIBAND (device), NULL);
 
-	priv = NM_DEVICE_INFINIBAND_GET_PRIVATE (device);
-	if (!priv->hw_address) {
-		priv->hw_address = _nm_object_get_string_property (NM_OBJECT (device),
-								   NM_DBUS_INTERFACE_DEVICE_INFINIBAND,
-								   DBUS_PROP_HW_ADDRESS,
-								   NULL);
-	}
-
-	return priv->hw_address;
+	_nm_object_ensure_inited (NM_OBJECT (device));
+	return NM_DEVICE_INFINIBAND_GET_PRIVATE (device)->hw_address;
 }
 
 /**
@@ -116,20 +106,10 @@ nm_device_infiniband_get_hw_address (NMDeviceInfiniband *device)
 gboolean
 nm_device_infiniband_get_carrier (NMDeviceInfiniband *device)
 {
-	NMDeviceInfinibandPrivate *priv;
-
 	g_return_val_if_fail (NM_IS_DEVICE_INFINIBAND (device), FALSE);
 
-	priv = NM_DEVICE_INFINIBAND_GET_PRIVATE (device);
-	if (!priv->carrier_valid) {
-		priv->carrier = _nm_object_get_boolean_property (NM_OBJECT (device),
-								 NM_DBUS_INTERFACE_DEVICE_INFINIBAND,
-								 DBUS_PROP_CARRIER,
-								 NULL);
-		priv->carrier_valid = TRUE;
-	}
-
-	return priv->carrier;
+	_nm_object_ensure_inited (NM_OBJECT (device));
+	return NM_DEVICE_INFINIBAND_GET_PRIVATE (device)->carrier;
 }
 
 static gboolean
@@ -171,7 +151,6 @@ nm_device_infiniband_init (NMDeviceInfiniband *device)
 	NMDeviceInfinibandPrivate *priv = NM_DEVICE_INFINIBAND_GET_PRIVATE (device);
 
 	priv->carrier = FALSE;
-	priv->carrier_valid = FALSE;
 }
 
 static void
diff --git a/libnm-glib/nm-device-modem.c b/libnm-glib/nm-device-modem.c
index a339cd4..e6dc5a2 100644
--- a/libnm-glib/nm-device-modem.c
+++ b/libnm-glib/nm-device-modem.c
@@ -71,20 +71,11 @@ enum {
 NMDeviceModemCapabilities
 nm_device_modem_get_modem_capabilities (NMDeviceModem *self)
 {
-	NMDeviceModemPrivate *priv;
-
 	g_return_val_if_fail (self != NULL, NM_DEVICE_MODEM_CAPABILITY_NONE);
 	g_return_val_if_fail (NM_IS_DEVICE_MODEM (self), NM_DEVICE_MODEM_CAPABILITY_NONE);
 
-	priv = NM_DEVICE_MODEM_GET_PRIVATE (self);
-	if (!priv->caps) {
-		priv->caps = _nm_object_get_uint_property (NM_OBJECT (self),
-		                                           NM_DBUS_INTERFACE_DEVICE_MODEM,
-		                                           DBUS_PROP_MODEM_CAPS,
-		                                           NULL);
-	}
-
-	return priv->caps;
+	_nm_object_ensure_inited (NM_OBJECT (self));
+	return NM_DEVICE_MODEM_GET_PRIVATE (self)->caps;
 }
 
 /**
@@ -101,20 +92,11 @@ nm_device_modem_get_modem_capabilities (NMDeviceModem *self)
 NMDeviceModemCapabilities
 nm_device_modem_get_current_capabilities (NMDeviceModem *self)
 {
-	NMDeviceModemPrivate *priv;
-
 	g_return_val_if_fail (self != NULL, NM_DEVICE_MODEM_CAPABILITY_NONE);
 	g_return_val_if_fail (NM_IS_DEVICE_MODEM (self), NM_DEVICE_MODEM_CAPABILITY_NONE);
 
-	priv = NM_DEVICE_MODEM_GET_PRIVATE (self);
-	if (!priv->current_caps) {
-		priv->current_caps = _nm_object_get_uint_property (NM_OBJECT (self),
-		                                                   NM_DBUS_INTERFACE_DEVICE_MODEM,
-		                                                   DBUS_PROP_CURRENT_CAPS,
-		                                                   NULL);
-	}
-
-	return priv->current_caps;
+	_nm_object_ensure_inited (NM_OBJECT (self));
+	return NM_DEVICE_MODEM_GET_PRIVATE (self)->current_caps;
 }
 
 static gboolean
diff --git a/libnm-glib/nm-device-wifi.c b/libnm-glib/nm-device-wifi.c
index 6ac9181..91106d3 100644
--- a/libnm-glib/nm-device-wifi.c
+++ b/libnm-glib/nm-device-wifi.c
@@ -53,7 +53,6 @@ typedef struct {
 	NM80211Mode mode;
 	guint32 rate;
 	NMAccessPoint *active_ap;
-	gboolean got_active_ap;
 	NMDeviceWifiCapabilities wireless_caps;
 	GPtrArray *aps;
 
@@ -121,19 +120,10 @@ nm_device_wifi_new (DBusGConnection *connection, const char *path)
 const char *
 nm_device_wifi_get_hw_address (NMDeviceWifi *device)
 {
-	NMDeviceWifiPrivate *priv;
-
 	g_return_val_if_fail (NM_IS_DEVICE_WIFI (device), NULL);
 
-	priv = NM_DEVICE_WIFI_GET_PRIVATE (device);
-	if (!priv->hw_address) {
-		priv->hw_address = _nm_object_get_string_property (NM_OBJECT (device),
-		                                                  NM_DBUS_INTERFACE_DEVICE_WIRELESS,
-		                                                  DBUS_PROP_HW_ADDRESS,
-		                                                  NULL);
-	}
-
-	return priv->hw_address;
+	_nm_object_ensure_inited (NM_OBJECT (device));
+	return NM_DEVICE_WIFI_GET_PRIVATE (device)->hw_address;
 }
 
 /**
@@ -148,19 +138,10 @@ nm_device_wifi_get_hw_address (NMDeviceWifi *device)
 const char *
 nm_device_wifi_get_permanent_hw_address (NMDeviceWifi *device)
 {
-	NMDeviceWifiPrivate *priv;
-
 	g_return_val_if_fail (NM_IS_DEVICE_WIFI (device), NULL);
 
-	priv = NM_DEVICE_WIFI_GET_PRIVATE (device);
-	if (!priv->perm_hw_address) {
-		priv->perm_hw_address = _nm_object_get_string_property (NM_OBJECT (device),
-		                                                        NM_DBUS_INTERFACE_DEVICE_WIRELESS,
-		                                                        DBUS_PROP_PERM_HW_ADDRESS,
-		                                                        NULL);
-	}
-
-	return priv->perm_hw_address;
+	_nm_object_ensure_inited (NM_OBJECT (device));
+	return NM_DEVICE_WIFI_GET_PRIVATE (device)->perm_hw_address;
 }
 
 /**
@@ -174,19 +155,10 @@ nm_device_wifi_get_permanent_hw_address (NMDeviceWifi *device)
 NM80211Mode
 nm_device_wifi_get_mode (NMDeviceWifi *device)
 {
-	NMDeviceWifiPrivate *priv;
-
 	g_return_val_if_fail (NM_IS_DEVICE_WIFI (device), 0);
 
-	priv = NM_DEVICE_WIFI_GET_PRIVATE (device);
-	if (!priv->mode) {
-		priv->mode = _nm_object_get_uint_property (NM_OBJECT (device),
-		                                          NM_DBUS_INTERFACE_DEVICE_WIRELESS,
-		                                          DBUS_PROP_MODE,
-		                                          NULL);
-	}
-
-	return priv->mode;
+	_nm_object_ensure_inited (NM_OBJECT (device));
+	return NM_DEVICE_WIFI_GET_PRIVATE (device)->mode;
 }
 
 /**
@@ -200,7 +172,6 @@ nm_device_wifi_get_mode (NMDeviceWifi *device)
 guint32
 nm_device_wifi_get_bitrate (NMDeviceWifi *device)
 {
-	NMDeviceWifiPrivate *priv;
 	NMDeviceState state;
 
 	g_return_val_if_fail (NM_IS_DEVICE_WIFI (device), 0);
@@ -217,15 +188,8 @@ nm_device_wifi_get_bitrate (NMDeviceWifi *device)
 		return 0;
 	}
 
-	priv = NM_DEVICE_WIFI_GET_PRIVATE (device);
-	if (!priv->rate) {
-		priv->rate = _nm_object_get_uint_property (NM_OBJECT (device),
-		                                         NM_DBUS_INTERFACE_DEVICE_WIRELESS,
-		                                         DBUS_PROP_BITRATE,
-		                                         NULL);
-	}
-
-	return priv->rate;
+	_nm_object_ensure_inited (NM_OBJECT (device));
+	return NM_DEVICE_WIFI_GET_PRIVATE (device)->rate;
 }
 
 /**
@@ -239,19 +203,10 @@ nm_device_wifi_get_bitrate (NMDeviceWifi *device)
 NMDeviceWifiCapabilities
 nm_device_wifi_get_capabilities (NMDeviceWifi *device)
 {
-	NMDeviceWifiPrivate *priv;
-
 	g_return_val_if_fail (NM_IS_DEVICE_WIFI (device), 0);
 
-	priv = NM_DEVICE_WIFI_GET_PRIVATE (device);
-	if (!priv->wireless_caps) {
-		priv->wireless_caps = _nm_object_get_uint_property (NM_OBJECT (device),
-		                                                   NM_DBUS_INTERFACE_DEVICE_WIRELESS,
-		                                                   DBUS_PROP_WIRELESS_CAPABILITIES,
-		                                                   NULL);
-	}
-
-	return priv->wireless_caps;
+	_nm_object_ensure_inited (NM_OBJECT (device));
+	return NM_DEVICE_WIFI_GET_PRIVATE (device)->wireless_caps;
 }
 
 /**
@@ -265,11 +220,7 @@ nm_device_wifi_get_capabilities (NMDeviceWifi *device)
 NMAccessPoint *
 nm_device_wifi_get_active_access_point (NMDeviceWifi *device)
 {
-	NMDeviceWifiPrivate *priv;
 	NMDeviceState state;
-	char *path;
-	GValue value = { 0, };
-	GError *error = NULL;
 
 	g_return_val_if_fail (NM_IS_DEVICE_WIFI (device), NULL);
 
@@ -289,23 +240,8 @@ nm_device_wifi_get_active_access_point (NMDeviceWifi *device)
 		break;
 	}
 
-	priv = NM_DEVICE_WIFI_GET_PRIVATE (device);
-	if (priv->got_active_ap == TRUE)
-		return priv->active_ap;
-
-	path = _nm_object_get_object_path_property (NM_OBJECT (device),
-	                                            NM_DBUS_INTERFACE_DEVICE_WIRELESS,
-	                                            DBUS_PROP_ACTIVE_ACCESS_POINT,
-	                                            &error);
-	if (error == NULL) {
-		g_value_init (&value, DBUS_TYPE_G_OBJECT_PATH);
-		g_value_take_boxed (&value, path);
-		demarshal_active_ap (NM_OBJECT (device), NULL, &value, &priv->active_ap);
-		g_value_unset (&value);
-	}
-	g_clear_error (&error);
-
-	return priv->active_ap;
+	_nm_object_ensure_inited (NM_OBJECT (device));
+	return NM_DEVICE_WIFI_GET_PRIVATE (device)->active_ap;
 }
 
 /**
@@ -652,8 +588,6 @@ demarshal_active_ap (NMObject *object, GParamSpec *pspec, GValue *value, gpointe
 		}
 	}
 
-	priv->got_active_ap = TRUE;
-
 	if (priv->active_ap) {
 		g_object_unref (priv->active_ap);
 		priv->active_ap = NULL;
diff --git a/libnm-glib/nm-device-wimax.c b/libnm-glib/nm-device-wimax.c
index d5e3a22..d9555a3 100644
--- a/libnm-glib/nm-device-wimax.c
+++ b/libnm-glib/nm-device-wimax.c
@@ -48,7 +48,6 @@ typedef struct {
 
 	char *hw_address;
 	NMWimaxNsp *active_nsp;
-	gboolean got_active_nsp;
 	GPtrArray *nsps;
 
 	guint center_freq;
@@ -121,19 +120,10 @@ nm_device_wimax_new (DBusGConnection *connection, const char *path)
 const char *
 nm_device_wimax_get_hw_address (NMDeviceWimax *wimax)
 {
-	NMDeviceWimaxPrivate *priv;
-
 	g_return_val_if_fail (NM_IS_DEVICE_WIMAX (wimax), NULL);
 
-	priv = NM_DEVICE_WIMAX_GET_PRIVATE (wimax);
-	if (!priv->hw_address) {
-		priv->hw_address = _nm_object_get_string_property (NM_OBJECT (wimax),
-		                                                   NM_DBUS_INTERFACE_DEVICE_WIMAX,
-		                                                   DBUS_PROP_HW_ADDRESS,
-		                                                   NULL);
-	}
-
-	return priv->hw_address;
+	_nm_object_ensure_inited (NM_OBJECT (wimax));
+	return NM_DEVICE_WIMAX_GET_PRIVATE (wimax)->hw_address;
 }
 
 /**
@@ -147,11 +137,7 @@ nm_device_wimax_get_hw_address (NMDeviceWimax *wimax)
 NMWimaxNsp *
 nm_device_wimax_get_active_nsp (NMDeviceWimax *wimax)
 {
-	NMDeviceWimaxPrivate *priv;
 	NMDeviceState state;
-	char *path;
-	GValue value = { 0, };
-	GError *error = NULL;
 
 	g_return_val_if_fail (NM_IS_DEVICE_WIMAX (wimax), NULL);
 
@@ -171,23 +157,8 @@ nm_device_wimax_get_active_nsp (NMDeviceWimax *wimax)
 		break;
 	}
 
-	priv = NM_DEVICE_WIMAX_GET_PRIVATE (wimax);
-	if (priv->got_active_nsp == TRUE)
-		return priv->active_nsp;
-
-	path = _nm_object_get_object_path_property (NM_OBJECT (wimax),
-	                                            NM_DBUS_INTERFACE_DEVICE_WIMAX,
-	                                            DBUS_PROP_ACTIVE_NSP,
-	                                            &error);
-	if (error == NULL) {
-		g_value_init (&value, DBUS_TYPE_G_OBJECT_PATH);
-		g_value_take_boxed (&value, path);
-		demarshal_active_nsp (NM_OBJECT (wimax), NULL, &value, &priv->active_nsp);
-		g_value_unset (&value);
-	}
-	g_clear_error (&error);
-
-	return priv->active_nsp;
+	_nm_object_ensure_inited (NM_OBJECT (wimax));
+	return NM_DEVICE_WIMAX_GET_PRIVATE (wimax)->active_nsp;
 }
 
 /**
@@ -360,18 +331,10 @@ clean_up_nsps (NMDeviceWimax *self, gboolean notify)
 guint
 nm_device_wimax_get_center_frequency (NMDeviceWimax *self)
 {
-	NMDeviceWimaxPrivate *priv;
-
 	g_return_val_if_fail (NM_IS_DEVICE_WIMAX (self), 0);
 
-	priv = NM_DEVICE_WIMAX_GET_PRIVATE (self);
-	if (!priv->center_freq) {
-		priv->center_freq = _nm_object_get_uint_property (NM_OBJECT (self),
-		                                                  NM_DBUS_INTERFACE_DEVICE_WIMAX,
-		                                                  DBUS_PROP_CENTER_FREQUENCY,
-		                                                  NULL);
-	}
-	return priv->center_freq;
+	_nm_object_ensure_inited (NM_OBJECT (self));
+	return NM_DEVICE_WIMAX_GET_PRIVATE (self)->center_freq;
 }
 
 /**
@@ -388,18 +351,10 @@ nm_device_wimax_get_center_frequency (NMDeviceWimax *self)
 gint
 nm_device_wimax_get_rssi (NMDeviceWimax *self)
 {
-	NMDeviceWimaxPrivate *priv;
-
 	g_return_val_if_fail (NM_IS_DEVICE_WIMAX (self), 0);
 
-	priv = NM_DEVICE_WIMAX_GET_PRIVATE (self);
-	if (!priv->rssi) {
-		priv->rssi = _nm_object_get_int_property (NM_OBJECT (self),
-		                                          NM_DBUS_INTERFACE_DEVICE_WIMAX,
-		                                          DBUS_PROP_RSSI,
-		                                          NULL);
-	}
-	return priv->rssi;
+	_nm_object_ensure_inited (NM_OBJECT (self));
+	return NM_DEVICE_WIMAX_GET_PRIVATE (self)->rssi;
 }
 
 /**
@@ -415,18 +370,10 @@ nm_device_wimax_get_rssi (NMDeviceWimax *self)
 gint
 nm_device_wimax_get_cinr (NMDeviceWimax *self)
 {
-	NMDeviceWimaxPrivate *priv;
-
 	g_return_val_if_fail (NM_IS_DEVICE_WIMAX (self), 0);
 
-	priv = NM_DEVICE_WIMAX_GET_PRIVATE (self);
-	if (!priv->cinr) {
-		priv->cinr = _nm_object_get_int_property (NM_OBJECT (self),
-		                                          NM_DBUS_INTERFACE_DEVICE_WIMAX,
-		                                          DBUS_PROP_CINR,
-		                                          NULL);
-	}
-	return priv->cinr;
+	_nm_object_ensure_inited (NM_OBJECT (self));
+	return NM_DEVICE_WIMAX_GET_PRIVATE (self)->cinr;
 }
 
 /**
@@ -442,18 +389,10 @@ nm_device_wimax_get_cinr (NMDeviceWimax *self)
 gint
 nm_device_wimax_get_tx_power (NMDeviceWimax *self)
 {
-	NMDeviceWimaxPrivate *priv;
-
 	g_return_val_if_fail (NM_IS_DEVICE_WIMAX (self), 0);
 
-	priv = NM_DEVICE_WIMAX_GET_PRIVATE (self);
-	if (!priv->tx_power) {
-		priv->tx_power = _nm_object_get_int_property (NM_OBJECT (self),
-		                                              NM_DBUS_INTERFACE_DEVICE_WIMAX,
-		                                              DBUS_PROP_TX_POWER,
-		                                              NULL);
-	}
-	return priv->tx_power;
+	_nm_object_ensure_inited (NM_OBJECT (self));
+	return NM_DEVICE_WIMAX_GET_PRIVATE (self)->tx_power;
 }
 
 /**
@@ -467,18 +406,10 @@ nm_device_wimax_get_tx_power (NMDeviceWimax *self)
 const char *
 nm_device_wimax_get_bsid (NMDeviceWimax *self)
 {
-	NMDeviceWimaxPrivate *priv;
-
 	g_return_val_if_fail (NM_IS_DEVICE_WIMAX (self), NULL);
 
-	priv = NM_DEVICE_WIMAX_GET_PRIVATE (self);
-	if (!priv->bsid) {
-		priv->bsid = _nm_object_get_string_property (NM_OBJECT (self),
-		                                             NM_DBUS_INTERFACE_DEVICE_WIMAX,
-		                                             DBUS_PROP_BSID,
-		                                             NULL);
-	}
-	return priv->bsid;
+	_nm_object_ensure_inited (NM_OBJECT (self));
+	return NM_DEVICE_WIMAX_GET_PRIVATE (self)->bsid;
 }
 
 static gboolean
@@ -643,8 +574,6 @@ demarshal_active_nsp (NMObject *object, GParamSpec *pspec, GValue *value, gpoint
 		}
 	}
 
-	priv->got_active_nsp = TRUE;
-
 	if (priv->active_nsp) {
 		g_object_unref (priv->active_nsp);
 		priv->active_nsp = NULL;
diff --git a/libnm-glib/nm-device.c b/libnm-glib/nm-device.c
index d051a39..208f415 100644
--- a/libnm-glib/nm-device.c
+++ b/libnm-glib/nm-device.c
@@ -56,17 +56,12 @@ typedef struct {
 	gboolean managed;
 	gboolean firmware_missing;
 	NMIP4Config *ip4_config;
-	gboolean got_ip4_config;
 	NMDHCP4Config *dhcp4_config;
-	gboolean got_dhcp4_config;
 	NMIP6Config *ip6_config;
-	gboolean got_ip6_config;
 	NMDHCP6Config *dhcp6_config;
-	gboolean got_dhcp6_config;
 	NMDeviceState state;
 
 	NMActiveConnection *active_connection;
-	gboolean got_active_connection;
 
 	GUdevClient *client;
 	char *product;
@@ -134,8 +129,6 @@ demarshal_ip4_config (NMObject *object, GParamSpec *pspec, GValue *value, gpoint
 		}
 	}
 
-	priv->got_ip4_config = TRUE;
-
 	if (priv->ip4_config) {
 		g_object_unref (priv->ip4_config);
 		priv->ip4_config = NULL;
@@ -170,8 +163,6 @@ demarshal_dhcp4_config (NMObject *object, GParamSpec *pspec, GValue *value, gpoi
 		}
 	}
 
-	priv->got_dhcp4_config = TRUE;
-
 	if (priv->dhcp4_config) {
 		g_object_unref (priv->dhcp4_config);
 		priv->dhcp4_config = NULL;
@@ -206,8 +197,6 @@ demarshal_ip6_config (NMObject *object, GParamSpec *pspec, GValue *value, gpoint
 		}
 	}
 
-	priv->got_ip6_config = TRUE;
-
 	if (priv->ip6_config) {
 		g_object_unref (priv->ip6_config);
 		priv->ip6_config = NULL;
@@ -242,8 +231,6 @@ demarshal_dhcp6_config (NMObject *object, GParamSpec *pspec, GValue *value, gpoi
 		}
 	}
 
-	priv->got_dhcp6_config = TRUE;
-
 	if (priv->dhcp6_config) {
 		g_object_unref (priv->dhcp6_config);
 		priv->dhcp6_config = NULL;
@@ -278,8 +265,6 @@ demarshal_active_connection (NMObject *object, GParamSpec *pspec, GValue *value,
 		}
 	}
 
-	priv->got_active_connection = TRUE;
-
 	if (priv->active_connection) {
 		g_object_unref (priv->active_connection);
 		priv->active_connection = NULL;
@@ -332,13 +317,9 @@ device_state_changed (DBusGProxy *proxy,
                       gpointer user_data)
 {
 	NMDevice *self = NM_DEVICE (user_data);
-	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
 
-	if (priv->state != new_state) {
-		priv->state = new_state;
+	if (old_state != new_state)
 		g_signal_emit (self, signals[STATE_CHANGED], 0, new_state, old_state, reason);
-		_nm_object_queue_notify (NM_OBJECT (self), "state");
-	}
 }
 
 static void
@@ -906,19 +887,10 @@ out:
 const char *
 nm_device_get_iface (NMDevice *device)
 {
-	NMDevicePrivate *priv;
-
 	g_return_val_if_fail (NM_IS_DEVICE (device), NULL);
 
-	priv = NM_DEVICE_GET_PRIVATE (device);
-	if (!priv->iface) {
-		priv->iface = _nm_object_get_string_property (NM_OBJECT (device),
-		                                             NM_DBUS_INTERFACE_DEVICE,
-		                                             "Interface",
-		                                             NULL);
-	}
-
-	return priv->iface;
+	_nm_object_ensure_inited (NM_OBJECT (device));
+	return NM_DEVICE_GET_PRIVATE (device)->iface;
 }
 
 /**
@@ -934,19 +906,10 @@ nm_device_get_iface (NMDevice *device)
 const char *
 nm_device_get_ip_iface (NMDevice *device)
 {
-	NMDevicePrivate *priv;
-
 	g_return_val_if_fail (NM_IS_DEVICE (device), NULL);
 
-	priv = NM_DEVICE_GET_PRIVATE (device);
-	if (!priv->ip_iface) {
-		priv->ip_iface = _nm_object_get_string_property (NM_OBJECT (device),
-		                                                 NM_DBUS_INTERFACE_DEVICE,
-		                                                 "IpInterface",
-		                                                 NULL);
-	}
-
-	return priv->ip_iface;
+	_nm_object_ensure_inited (NM_OBJECT (device));
+	return NM_DEVICE_GET_PRIVATE (device)->ip_iface;
 }
 
 /**
@@ -978,19 +941,10 @@ nm_device_get_device_type (NMDevice *self)
 const char *
 nm_device_get_udi (NMDevice *device)
 {
-	NMDevicePrivate *priv;
-
 	g_return_val_if_fail (NM_IS_DEVICE (device), NULL);
 
-	priv = NM_DEVICE_GET_PRIVATE (device);
-	if (!priv->udi) {
-		priv->udi = _nm_object_get_string_property (NM_OBJECT (device),
-		                                           NM_DBUS_INTERFACE_DEVICE,
-		                                           "Udi",
-		                                           NULL);
-	}
-
-	return priv->udi;
+	_nm_object_ensure_inited (NM_OBJECT (device));
+	return NM_DEVICE_GET_PRIVATE (device)->udi;
 }
 
 /**
@@ -1005,19 +959,10 @@ nm_device_get_udi (NMDevice *device)
 const char *
 nm_device_get_driver (NMDevice *device)
 {
-	NMDevicePrivate *priv;
-
 	g_return_val_if_fail (NM_IS_DEVICE (device), NULL);
 
-	priv = NM_DEVICE_GET_PRIVATE (device);
-	if (!priv->driver) {
-		priv->driver = _nm_object_get_string_property (NM_OBJECT (device),
-		                                              NM_DBUS_INTERFACE_DEVICE,
-		                                              "Driver",
-		                                              NULL);
-	}
-
-	return priv->driver;
+	_nm_object_ensure_inited (NM_OBJECT (device));
+	return NM_DEVICE_GET_PRIVATE (device)->driver;
 }
 
 /**
@@ -1031,19 +976,10 @@ nm_device_get_driver (NMDevice *device)
 NMDeviceCapabilities
 nm_device_get_capabilities (NMDevice *device)
 {
-	NMDevicePrivate *priv;
-
 	g_return_val_if_fail (NM_IS_DEVICE (device), 0);
 
-	priv = NM_DEVICE_GET_PRIVATE (device);
-	if (!priv->capabilities) {
-		priv->capabilities = _nm_object_get_uint_property (NM_OBJECT (device),
-		                                                  NM_DBUS_INTERFACE_DEVICE,
-		                                                  "Capabilities",
-		                                                  NULL);
-	}
-
-	return priv->capabilities;
+	_nm_object_ensure_inited (NM_OBJECT (device));
+	return NM_DEVICE_GET_PRIVATE (device)->capabilities;
 }
 
 /**
@@ -1057,19 +993,10 @@ nm_device_get_capabilities (NMDevice *device)
 gboolean
 nm_device_get_managed (NMDevice *device)
 {
-	NMDevicePrivate *priv;
-
 	g_return_val_if_fail (NM_IS_DEVICE (device), 0);
 
-	priv = NM_DEVICE_GET_PRIVATE (device);
-	if (!priv->managed) {
-		priv->managed = _nm_object_get_boolean_property (NM_OBJECT (device),
-		                                                NM_DBUS_INTERFACE_DEVICE,
-		                                                "Managed",
-		                                                NULL);
-	}
-
-	return priv->managed;
+	_nm_object_ensure_inited (NM_OBJECT (device));
+	return NM_DEVICE_GET_PRIVATE (device)->managed;
 }
 
 /**
@@ -1085,19 +1012,10 @@ nm_device_get_managed (NMDevice *device)
 gboolean
 nm_device_get_firmware_missing (NMDevice *device)
 {
-	NMDevicePrivate *priv;
-
 	g_return_val_if_fail (NM_IS_DEVICE (device), 0);
 
-	priv = NM_DEVICE_GET_PRIVATE (device);
-	if (!priv->firmware_missing) {
-		priv->firmware_missing = _nm_object_get_boolean_property (NM_OBJECT (device),
-		                                                          NM_DBUS_INTERFACE_DEVICE,
-		                                                          "FirmwareMissing",
-		                                                          NULL);
-	}
-
-	return priv->firmware_missing;
+	_nm_object_ensure_inited (NM_OBJECT (device));
+	return NM_DEVICE_GET_PRIVATE (device)->firmware_missing;
 }
 
 /**
@@ -1111,30 +1029,10 @@ nm_device_get_firmware_missing (NMDevice *device)
 NMIP4Config *
 nm_device_get_ip4_config (NMDevice *device)
 {
-	NMDevicePrivate *priv;
-	char *path;
-	GValue value = { 0, };
-	GError *error = NULL;
-
 	g_return_val_if_fail (NM_IS_DEVICE (device), NULL);
 
-	priv = NM_DEVICE_GET_PRIVATE (device);
-	if (priv->got_ip4_config == TRUE)
-		return priv->ip4_config;
-
-	path = _nm_object_get_object_path_property (NM_OBJECT (device),
-	                                            NM_DBUS_INTERFACE_DEVICE,
-	                                            "Ip4Config",
-	                                            &error);
-	if (error == NULL) {
-		g_value_init (&value, DBUS_TYPE_G_OBJECT_PATH);
-		g_value_take_boxed (&value, path);
-		demarshal_ip4_config (NM_OBJECT (device), NULL, &value, &priv->ip4_config);
-		g_value_unset (&value);
-	}
-	g_clear_error (&error);
-
-	return priv->ip4_config;
+	_nm_object_ensure_inited (NM_OBJECT (device));
+	return NM_DEVICE_GET_PRIVATE (device)->ip4_config;
 }
 
 /**
@@ -1149,30 +1047,10 @@ nm_device_get_ip4_config (NMDevice *device)
 NMDHCP4Config *
 nm_device_get_dhcp4_config (NMDevice *device)
 {
-	NMDevicePrivate *priv;
-	char *path;
-	GValue value = { 0, };
-	GError *error = NULL;
-
 	g_return_val_if_fail (NM_IS_DEVICE (device), NULL);
 
-	priv = NM_DEVICE_GET_PRIVATE (device);
-	if (priv->got_dhcp4_config == TRUE)
-		return priv->dhcp4_config;
-
-	path = _nm_object_get_object_path_property (NM_OBJECT (device),
-	                                            NM_DBUS_INTERFACE_DEVICE,
-	                                            "Dhcp4Config",
-	                                            &error);
-	if (error == NULL) {
-		g_value_init (&value, DBUS_TYPE_G_OBJECT_PATH);
-		g_value_take_boxed (&value, path);
-		demarshal_dhcp4_config (NM_OBJECT (device), NULL, &value, &priv->dhcp4_config);
-		g_value_unset (&value);
-	}
-	g_clear_error (&error);
-
-	return priv->dhcp4_config;
+	_nm_object_ensure_inited (NM_OBJECT (device));
+	return NM_DEVICE_GET_PRIVATE (device)->dhcp4_config;
 }
 
 /**
@@ -1186,30 +1064,10 @@ nm_device_get_dhcp4_config (NMDevice *device)
 NMIP6Config *
 nm_device_get_ip6_config (NMDevice *device)
 {
-	NMDevicePrivate *priv;
-	char *path;
-	GValue value = { 0, };
-	GError *error = NULL;
-
 	g_return_val_if_fail (NM_IS_DEVICE (device), NULL);
 
-	priv = NM_DEVICE_GET_PRIVATE (device);
-	if (priv->got_ip6_config == TRUE)
-		return priv->ip6_config;
-
-	path = _nm_object_get_object_path_property (NM_OBJECT (device),
-	                                            NM_DBUS_INTERFACE_DEVICE,
-	                                            "Ip6Config",
-	                                            &error);
-	if (error == NULL) {
-		g_value_init (&value, DBUS_TYPE_G_OBJECT_PATH);
-		g_value_take_boxed (&value, path);
-		demarshal_ip6_config (NM_OBJECT (device), NULL, &value, &priv->ip6_config);
-		g_value_unset (&value);
-	}
-	g_clear_error (&error);
-
-	return priv->ip6_config;
+	_nm_object_ensure_inited (NM_OBJECT (device));
+	return NM_DEVICE_GET_PRIVATE (device)->ip6_config;
 }
 
 /**
@@ -1224,30 +1082,10 @@ nm_device_get_ip6_config (NMDevice *device)
 NMDHCP6Config *
 nm_device_get_dhcp6_config (NMDevice *device)
 {
-	NMDevicePrivate *priv;
-	char *path;
-	GValue value = { 0, };
-	GError *error = NULL;
-
 	g_return_val_if_fail (NM_IS_DEVICE (device), NULL);
 
-	priv = NM_DEVICE_GET_PRIVATE (device);
-	if (priv->got_dhcp6_config == TRUE)
-		return priv->dhcp6_config;
-
-	path = _nm_object_get_object_path_property (NM_OBJECT (device),
-	                                            NM_DBUS_INTERFACE_DEVICE,
-	                                            "Dhcp6Config",
-	                                            &error);
-	if (error == NULL) {
-		g_value_init (&value, DBUS_TYPE_G_OBJECT_PATH);
-		g_value_take_boxed (&value, path);
-		demarshal_dhcp6_config (NM_OBJECT (device), NULL, &value, &priv->dhcp6_config);
-		g_value_unset (&value);
-	}
-	g_clear_error (&error);
-
-	return priv->dhcp6_config;
+	_nm_object_ensure_inited (NM_OBJECT (device));
+	return NM_DEVICE_GET_PRIVATE (device)->dhcp6_config;
 }
 
 /**
@@ -1261,19 +1099,10 @@ nm_device_get_dhcp6_config (NMDevice *device)
 NMDeviceState
 nm_device_get_state (NMDevice *device)
 {
-	NMDevicePrivate *priv;
-
 	g_return_val_if_fail (NM_IS_DEVICE (device), NM_DEVICE_STATE_UNKNOWN);
 
-	priv = NM_DEVICE_GET_PRIVATE (device);
-	if (priv->state == NM_DEVICE_STATE_UNKNOWN) {
-		priv->state = _nm_object_get_uint_property (NM_OBJECT (device), 
-		                                           NM_DBUS_INTERFACE_DEVICE,
-		                                           "State",
-		                                           NULL);
-	}
-
-	return priv->state;
+	_nm_object_ensure_inited (NM_OBJECT (device));
+	return NM_DEVICE_GET_PRIVATE (device)->state;
 }
 
 /**
@@ -1288,30 +1117,10 @@ nm_device_get_state (NMDevice *device)
 NMActiveConnection *
 nm_device_get_active_connection (NMDevice *device)
 {
-	NMDevicePrivate *priv;
-	char *path;
-	GValue value = { 0, };
-	GError *error = NULL;
-
 	g_return_val_if_fail (NM_IS_DEVICE (device), NULL);
 
-	priv = NM_DEVICE_GET_PRIVATE (device);
-	if (priv->got_active_connection == TRUE)
-		return priv->active_connection;
-
-	path = _nm_object_get_object_path_property (NM_OBJECT (device),
-	                                            NM_DBUS_INTERFACE_DEVICE,
-	                                            "ActiveConnection",
-	                                            &error);
-	if (error == NULL) {
-		g_value_init (&value, DBUS_TYPE_G_OBJECT_PATH);
-		g_value_take_boxed (&value, path);
-		demarshal_active_connection (NM_OBJECT (device), NULL, &value, &priv->active_connection);
-		g_value_unset (&value);
-	}
-	g_clear_error (&error);
-
-	return priv->active_connection;
+	_nm_object_ensure_inited (NM_OBJECT (device));
+	return NM_DEVICE_GET_PRIVATE (device)->active_connection;
 }
 
 /* From hostap, Copyright (c) 2002-2005, Jouni Malinen <jkmaline cc hut fi> */
diff --git a/libnm-glib/nm-dhcp4-config.c b/libnm-glib/nm-dhcp4-config.c
index e3fe2c6..06c292d 100644
--- a/libnm-glib/nm-dhcp4-config.c
+++ b/libnm-glib/nm-dhcp4-config.c
@@ -212,24 +212,10 @@ nm_dhcp4_config_new (DBusGConnection *connection, const char *object_path)
 GHashTable *
 nm_dhcp4_config_get_options (NMDHCP4Config *config)
 {
-	NMDHCP4ConfigPrivate *priv = NM_DHCP4_CONFIG_GET_PRIVATE (config);
-	GValue value = { 0, };
-
-	if (g_hash_table_size (priv->options))
-		return priv->options;
-
-	if (!_nm_object_get_property (NM_OBJECT (config),
-	                              NM_DBUS_INTERFACE_DHCP4_CONFIG,
-	                              "Options",
-	                              &value,
-	                              NULL))
-		goto out;
-
-	demarshal_dhcp4_options (NM_OBJECT (config), NULL, &value, &priv->options);	
-	g_value_unset (&value);
+	g_return_val_if_fail (NM_IS_DHCP4_CONFIG (config), NULL);
 
-out:
-	return priv->options;
+	_nm_object_ensure_inited (NM_OBJECT (config));
+	return NM_DHCP4_CONFIG_GET_PRIVATE (config)->options;
 }
 
 /**
diff --git a/libnm-glib/nm-dhcp6-config.c b/libnm-glib/nm-dhcp6-config.c
index c282a27..84eb88f 100644
--- a/libnm-glib/nm-dhcp6-config.c
+++ b/libnm-glib/nm-dhcp6-config.c
@@ -212,24 +212,10 @@ nm_dhcp6_config_new (DBusGConnection *connection, const char *object_path)
 GHashTable *
 nm_dhcp6_config_get_options (NMDHCP6Config *config)
 {
-	NMDHCP6ConfigPrivate *priv = NM_DHCP6_CONFIG_GET_PRIVATE (config);
-	GValue value = { 0, };
-
-	if (g_hash_table_size (priv->options))
-		return priv->options;
-
-	if (!_nm_object_get_property (NM_OBJECT (config),
-	                              NM_DBUS_INTERFACE_DHCP6_CONFIG,
-	                              "Options",
-	                              &value,
-	                              NULL))
-		goto out;
-
-	demarshal_dhcp6_options (NM_OBJECT (config), NULL, &value, &priv->options);	
-	g_value_unset (&value);
+	g_return_val_if_fail (NM_IS_DHCP6_CONFIG (config), NULL);
 
-out:
-	return priv->options;
+	_nm_object_ensure_inited (NM_OBJECT (config));
+	return NM_DHCP6_CONFIG_GET_PRIVATE (config)->options;
 }
 
 /**
diff --git a/libnm-glib/nm-ip4-config.c b/libnm-glib/nm-ip4-config.c
index 7706d05..3ea5db0 100644
--- a/libnm-glib/nm-ip4-config.c
+++ b/libnm-glib/nm-ip4-config.c
@@ -326,27 +326,10 @@ nm_ip4_config_new (DBusGConnection *connection, const char *object_path)
 const GSList *
 nm_ip4_config_get_addresses (NMIP4Config *config)
 {
-	NMIP4ConfigPrivate *priv;
-	GValue value = { 0, };
-
 	g_return_val_if_fail (NM_IS_IP4_CONFIG (config), NULL);
 
-	priv = NM_IP4_CONFIG_GET_PRIVATE (config);
-	if (priv->addresses)
-		return priv->addresses;
-
-	if (!_nm_object_get_property (NM_OBJECT (config),
-	                              NM_DBUS_INTERFACE_IP4_CONFIG,
-	                              "Addresses",
-	                              &value,
-	                              NULL)) {
-		return NULL;
-	}
-
-	demarshal_ip4_address_array (NM_OBJECT (config), NULL, &value, &priv->addresses);	
-	g_value_unset (&value);
-
-	return priv->addresses;
+	_nm_object_ensure_inited (NM_OBJECT (config));
+	return NM_IP4_CONFIG_GET_PRIVATE (config)->addresses;
 }
 
 /**
@@ -361,29 +344,10 @@ nm_ip4_config_get_addresses (NMIP4Config *config)
 const GArray *
 nm_ip4_config_get_nameservers (NMIP4Config *config)
 {
-	NMIP4ConfigPrivate *priv;
-	GArray *array = NULL;
-	GValue value = {0,};
-
 	g_return_val_if_fail (NM_IS_IP4_CONFIG (config), NULL);
 
-	priv = NM_IP4_CONFIG_GET_PRIVATE (config);
-	if (!priv->nameservers) {
-		if (_nm_object_get_property (NM_OBJECT (config),
-		                             NM_DBUS_INTERFACE_IP4_CONFIG,
-		                             "Nameservers",
-		                             &value,
-		                             NULL)) {
-			array = (GArray *) g_value_get_boxed (&value);
-			if (array && array->len) {
-				priv->nameservers = g_array_sized_new (FALSE, TRUE, sizeof (guint32), array->len);
-				g_array_append_vals (priv->nameservers, array->data, array->len);
-			}
-			g_value_unset (&value);
-		}
-	}
-
-	return priv->nameservers;
+	_nm_object_ensure_inited (NM_OBJECT (config));
+	return NM_IP4_CONFIG_GET_PRIVATE (config)->nameservers;
 }
 
 /**
@@ -398,32 +362,10 @@ nm_ip4_config_get_nameservers (NMIP4Config *config)
 const GPtrArray *
 nm_ip4_config_get_domains (NMIP4Config *config)
 {
-	NMIP4ConfigPrivate *priv;
-	GValue value = {0,};
-
 	g_return_val_if_fail (NM_IS_IP4_CONFIG (config), NULL);
 
-	priv = NM_IP4_CONFIG_GET_PRIVATE (config);
-	if (priv->domains)
-		return handle_ptr_array_return (priv->domains);
-
-	if (_nm_object_get_property (NM_OBJECT (config),
-	                             NM_DBUS_INTERFACE_IP4_CONFIG,
-	                             "Domains",
-	                             &value,
-	                             NULL)) {
-		char **array = NULL, **p;
-
-		array = (char **) g_value_get_boxed (&value);
-		if (array && g_strv_length (array)) {
-			priv->domains = g_ptr_array_sized_new (g_strv_length (array));
-			for (p = array; *p; p++)
-				g_ptr_array_add (priv->domains, g_strdup (*p));
-		}
-		g_value_unset (&value);
-	}
-
-	return handle_ptr_array_return (priv->domains);
+	_nm_object_ensure_inited (NM_OBJECT (config));
+	return handle_ptr_array_return (NM_IP4_CONFIG_GET_PRIVATE (config)->domains);
 }
 
 /**
@@ -438,29 +380,10 @@ nm_ip4_config_get_domains (NMIP4Config *config)
 const GArray *
 nm_ip4_config_get_wins_servers (NMIP4Config *config)
 {
-	NMIP4ConfigPrivate *priv;
-	GArray *array = NULL;
-	GValue value = {0,};
-
 	g_return_val_if_fail (NM_IS_IP4_CONFIG (config), NULL);
 
-	priv = NM_IP4_CONFIG_GET_PRIVATE (config);
-	if (!priv->wins) {
-		if (_nm_object_get_property (NM_OBJECT (config),
-		                             NM_DBUS_INTERFACE_IP4_CONFIG,
-		                             "WinsServers",
-		                             &value,
-		                             NULL)) {
-			array = (GArray *) g_value_get_boxed (&value);
-			if (array && array->len) {
-				priv->wins = g_array_sized_new (FALSE, TRUE, sizeof (guint32), array->len);
-				g_array_append_vals (priv->wins, array->data, array->len);
-			}
-			g_value_unset (&value);
-		}
-	}
-
-	return priv->wins;
+	_nm_object_ensure_inited (NM_OBJECT (config));
+	return NM_IP4_CONFIG_GET_PRIVATE (config)->wins;
 }
 
 /**
@@ -476,26 +399,9 @@ nm_ip4_config_get_wins_servers (NMIP4Config *config)
 const GSList *
 nm_ip4_config_get_routes (NMIP4Config *config)
 {
-	NMIP4ConfigPrivate *priv;
-	GValue value = { 0, };
-
 	g_return_val_if_fail (NM_IS_IP4_CONFIG (config), NULL);
 
-	priv = NM_IP4_CONFIG_GET_PRIVATE (config);
-	if (priv->routes)
-		return priv->routes;
-
-	if (!_nm_object_get_property (NM_OBJECT (config),
-	                              NM_DBUS_INTERFACE_IP4_CONFIG,
-	                              "Routes",
-	                              &value,
-	                              NULL)) {
-		return NULL;
-	}
-
-	demarshal_ip4_routes_array (NM_OBJECT (config), NULL, &value, &priv->routes);
-	g_value_unset (&value);
-
-	return priv->routes;
+	_nm_object_ensure_inited (NM_OBJECT (config));
+	return NM_IP4_CONFIG_GET_PRIVATE (config)->routes;
 }
 
diff --git a/libnm-glib/nm-ip6-config.c b/libnm-glib/nm-ip6-config.c
index f62ab82..0184226 100644
--- a/libnm-glib/nm-ip6-config.c
+++ b/libnm-glib/nm-ip6-config.c
@@ -153,27 +153,10 @@ register_properties (NMIP6Config *config)
 const GSList *
 nm_ip6_config_get_addresses (NMIP6Config *config)
 {
-	NMIP6ConfigPrivate *priv;
-	GValue value = { 0, };
-
 	g_return_val_if_fail (NM_IS_IP6_CONFIG (config), NULL);
 
-	priv = NM_IP6_CONFIG_GET_PRIVATE (config);
-	if (priv->addresses)
-		return priv->addresses;
-
-	if (!_nm_object_get_property (NM_OBJECT (config),
-	                              NM_DBUS_INTERFACE_IP6_CONFIG,
-	                              "Addresses",
-	                              &value,
-	                              NULL)) {
-		return NULL;
-	}
-
-	demarshal_ip6_address_array (NM_OBJECT (config), NULL, &value, &priv->addresses);	
-	g_value_unset (&value);
-
-	return priv->addresses;
+	_nm_object_ensure_inited (NM_OBJECT (config));
+	return NM_IP6_CONFIG_GET_PRIVATE (config)->addresses;
 }
 
 /* FIXME: like in libnm_util, in6_addr is not introspectable, so skipping here */
@@ -190,29 +173,10 @@ nm_ip6_config_get_addresses (NMIP6Config *config)
 const GSList *
 nm_ip6_config_get_nameservers (NMIP6Config *config)
 {
-	NMIP6ConfigPrivate *priv;
-	GParamSpec *pspec;
-	GValue value = {0,};
-
 	g_return_val_if_fail (NM_IS_IP6_CONFIG (config), NULL);
 
-	priv = NM_IP6_CONFIG_GET_PRIVATE (config);
-	if (priv->nameservers)
-		return priv->nameservers;
-
-	if (!_nm_object_get_property (NM_OBJECT (config),
-	                              NM_DBUS_INTERFACE_IP6_CONFIG,
-	                              "Nameservers",
-	                              &value,
-	                              NULL)) {
-		return NULL;
-	}
-
-	pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (G_OBJECT (config)), NM_IP6_CONFIG_NAMESERVERS);
-	demarshal_ip6_nameserver_array (NM_OBJECT (config), pspec, &value, &priv->nameservers);
-	g_value_unset (&value);
-
-	return priv->nameservers;
+	_nm_object_ensure_inited (NM_OBJECT (config));
+	return NM_IP6_CONFIG_GET_PRIVATE (config)->nameservers;
 }
 
 /**
@@ -227,27 +191,10 @@ nm_ip6_config_get_nameservers (NMIP6Config *config)
 const GPtrArray *
 nm_ip6_config_get_domains (NMIP6Config *config)
 {
-	NMIP6ConfigPrivate *priv;
-	GValue value = {0,};
-
 	g_return_val_if_fail (NM_IS_IP6_CONFIG (config), NULL);
 
-	priv = NM_IP6_CONFIG_GET_PRIVATE (config);
-	if (priv->domains)
-		return handle_ptr_array_return (priv->domains);
-
-	if (!_nm_object_get_property (NM_OBJECT (config),
-	                              NM_DBUS_INTERFACE_IP6_CONFIG,
-	                              "Domains",
-	                              &value,
-	                              NULL)) {
-		return NULL;
-	}
-
-	demarshal_domains (NM_OBJECT (config), NULL, &value, &priv->domains);
-	g_value_unset (&value);
-
-	return handle_ptr_array_return (priv->domains);
+	_nm_object_ensure_inited (NM_OBJECT (config));
+	return handle_ptr_array_return (NM_IP6_CONFIG_GET_PRIVATE (config)->domains);
 }
 
 /**
@@ -263,27 +210,10 @@ nm_ip6_config_get_domains (NMIP6Config *config)
 const GSList *
 nm_ip6_config_get_routes (NMIP6Config *config)
 {
-	NMIP6ConfigPrivate *priv;
-	GValue value = { 0, };
-
 	g_return_val_if_fail (NM_IS_IP6_CONFIG (config), NULL);
 
-	priv = NM_IP6_CONFIG_GET_PRIVATE (config);
-	if (priv->routes)
-		return priv->routes;
-
-	if (!_nm_object_get_property (NM_OBJECT (config),
-	                              NM_DBUS_INTERFACE_IP6_CONFIG,
-	                              "Routes",
-	                              &value,
-	                              NULL)) {
-		return NULL;
-	}
-
-	demarshal_ip6_routes_array (NM_OBJECT (config), NULL, &value, &priv->routes);
-	g_value_unset (&value);
-
-	return priv->routes;
+	_nm_object_ensure_inited (NM_OBJECT (config));
+	return NM_IP6_CONFIG_GET_PRIVATE (config)->routes;
 }
 
 static GObject*
diff --git a/libnm-glib/nm-object-private.h b/libnm-glib/nm-object-private.h
index c01507d..7b14ad6 100644
--- a/libnm-glib/nm-object-private.h
+++ b/libnm-glib/nm-object-private.h
@@ -27,6 +27,8 @@
 #include <glib-object.h>
 #include "nm-object.h"
 
+void _nm_object_ensure_inited (NMObject *object);
+
 typedef gboolean (*PropertyMarshalFunc) (NMObject *, GParamSpec *, GValue *, gpointer);
 typedef GObject * (*NMObjectCreatorFunc) (DBusGConnection *, const char *);
 
@@ -41,63 +43,23 @@ void _nm_object_register_properties (NMObject *object,
 									 DBusGProxy *proxy,
 									 const NMPropertiesInfo *info);
 
+gboolean _nm_object_reload_properties (NMObject *object, GError **error);
+
 void _nm_object_process_properties_changed (NMObject *self, GHashTable *properties);
 
 void _nm_object_queue_notify (NMObject *object, const char *property);
 
 /* DBus property accessors */
 
-gboolean _nm_object_get_property (NMObject *object,
-                                  const char *interface,
-                                  const char *prop_name,
-                                  GValue *value,
-                                  GError **error);
+void _nm_object_reload_property (NMObject *object,
+                                 const char *interface,
+                                 const char *prop_name);
 
 void _nm_object_set_property (NMObject *object,
                               const char *interface,
                               const char *prop_name,
                               GValue *value);
 
-char *_nm_object_get_string_property (NMObject *object,
-                                      const char *interface,
-                                      const char *prop_name,
-                                      GError **error);
-
-char *_nm_object_get_object_path_property (NMObject *object,
-                                           const char *interface,
-                                           const char *prop_name,
-                                           GError **error);
-
-gint32 _nm_object_get_int_property (NMObject *object,
-                                    const char *interface,
-                                    const char *prop_name,
-                                    GError **error);
-
-guint32 _nm_object_get_uint_property (NMObject *object,
-                                      const char *interface,
-                                      const char *prop_name,
-                                      GError **error);
-
-gboolean _nm_object_get_boolean_property (NMObject *object,
-                                          const char *interface,
-                                          const char *prop_name,
-                                          GError **error);
-
-gint8 _nm_object_get_byte_property (NMObject *object,
-                                    const char *interface,
-                                    const char *prop_name,
-                                    GError **error);
-
-gdouble _nm_object_get_double_property (NMObject *object,
-                                        const char *interface,
-                                        const char *prop_name,
-                                        GError **error);
-
-GByteArray *_nm_object_get_byte_array_property (NMObject *object,
-                                                const char *interface,
-                                                const char *prop_name,
-                                                GError **error);
-
 static inline const GPtrArray *
 handle_ptr_array_return (GPtrArray *array)
 {
diff --git a/libnm-glib/nm-object.c b/libnm-glib/nm-object.c
index e606650..5eb7a0a 100644
--- a/libnm-glib/nm-object.c
+++ b/libnm-glib/nm-object.c
@@ -52,7 +52,7 @@ typedef struct {
 
 	GSList *notify_props;
 	guint32 notify_id;
-	gboolean disposed;
+	gboolean inited, disposed;
 } NMObjectPrivate;
 
 enum {
@@ -515,33 +515,71 @@ _nm_object_register_properties (NMObject *object,
 }
 
 gboolean
-_nm_object_get_property (NMObject *object,
-                         const char *interface,
-                         const char *prop_name,
-                         GValue *value,
-                         GError **error)
+_nm_object_reload_properties (NMObject *object, GError **error)
 {
+	NMObjectPrivate *priv = NM_OBJECT_GET_PRIVATE (object);
+	GHashTable *props = NULL;
+	GSList *p;
+
+	if (!priv->property_interfaces)
+		return TRUE;
+
+	priv->inited = TRUE;
+
+	for (p = priv->property_interfaces; p; p = p->next) {
+		if (!dbus_g_proxy_call (priv->properties_proxy, "GetAll", error,
+		                        G_TYPE_STRING, p->data,
+		                        G_TYPE_INVALID,
+		                        DBUS_TYPE_G_MAP_OF_VARIANT, &props,
+		                        G_TYPE_INVALID))
+			return FALSE;
+
+		_nm_object_process_properties_changed (object, props);
+		g_hash_table_destroy (props);
+	}
+
+	return TRUE;
+}
+
+void
+_nm_object_ensure_inited (NMObject *object)
+{
+	NMObjectPrivate *priv = NM_OBJECT_GET_PRIVATE (object);
+	GError *error = NULL;
+
+	if (!priv->inited) {
+		if (!_nm_object_reload_properties (object, &error)) {
+			g_warning ("Could not initialize %s %s: %s",
+			           G_OBJECT_TYPE_NAME (object), priv->path,
+			           error->message);
+			g_error_free (error);
+		}
+	}
+}
+
+void
+_nm_object_reload_property (NMObject *object,
+                            const char *interface,
+                            const char *prop_name)
+{
+	GValue value = { 0, };
 	GError *err = NULL;
 
-	g_return_val_if_fail (NM_IS_OBJECT (object), FALSE);
-	g_return_val_if_fail (interface != NULL, FALSE);
-	g_return_val_if_fail (prop_name != NULL, FALSE);
-	g_return_val_if_fail (value != NULL, FALSE);
-	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+	g_return_if_fail (NM_IS_OBJECT (object));
+	g_return_if_fail (interface != NULL);
+	g_return_if_fail (prop_name != NULL);
 
 	if (!dbus_g_proxy_call_with_timeout (NM_OBJECT_GET_PRIVATE (object)->properties_proxy,
 							"Get", 15000, &err,
 							G_TYPE_STRING, interface,
 							G_TYPE_STRING, prop_name,
 							G_TYPE_INVALID,
-							G_TYPE_VALUE, value,
+							G_TYPE_VALUE, &value,
 							G_TYPE_INVALID)) {
 		/* Don't warn about D-Bus no reply/timeout errors; it's mostly noise and
 		 * happens for example when NM quits and the applet is still running.
-		 * And don't warn when 'error' is not NULL, rather propagate 'err' so the caller
-		 * can do something with it. */
-		if (   !error
-		    && !(err->domain == DBUS_GERROR && err->code == DBUS_GERROR_NO_REPLY)) {
+		 */
+		if (!g_error_matches (err, DBUS_GERROR, DBUS_GERROR_NO_REPLY)) {
 			g_warning ("%s: Error getting '%s' for %s: (%d) %s\n",
 			           __func__,
 			           prop_name,
@@ -549,11 +587,12 @@ _nm_object_get_property (NMObject *object,
 			           err->code,
 			           err->message);
 		}
-		g_propagate_error (error, err);
-		return FALSE;
+		g_clear_error (&err);
+		return;
 	}
 
-	return TRUE;
+	handle_property_changed ((gpointer)prop_name, &value, object);
+	g_value_unset (&value);
 }
 
 void
@@ -579,158 +618,3 @@ _nm_object_set_property (NMObject *object,
 		 */
 	}
 }
-
-char *
-_nm_object_get_string_property (NMObject *object,
-                                const char *interface,
-                                const char *prop_name,
-                                GError **error)
-{
-	char *str = NULL;
-	const char *tmp;
-	GValue value = {0,};
-
-	if (_nm_object_get_property (object, interface, prop_name, &value, error)) {
-		if (G_VALUE_HOLDS_STRING (&value))
-			str = g_strdup (g_value_get_string (&value));
-		else if (G_VALUE_HOLDS (&value, DBUS_TYPE_G_OBJECT_PATH)) {
-			tmp = g_value_get_boxed (&value);
-			/* Handle "NULL" object paths */
-			if (g_strcmp0 (tmp, "/") != 0)
-				str = g_strdup (tmp);
-		}
-		g_value_unset (&value);
-	}
-
-	return str;
-}
-
-char *
-_nm_object_get_object_path_property (NMObject *object,
-                                     const char *interface,
-                                     const char *prop_name,
-                                     GError **error)
-{
-	char *path = NULL;
-	const char *tmp;
-	GValue value = {0,};
-
-	if (_nm_object_get_property (object, interface, prop_name, &value, error)) {
-		tmp = g_value_get_boxed (&value);
-		if (g_strcmp0 (tmp, "/") != 0)
-			path = g_strdup (tmp);
-		g_value_unset (&value);
-	}
-
-	return path;
-}
-
-gint32
-_nm_object_get_int_property (NMObject *object,
-                             const char *interface,
-                             const char *prop_name,
-                             GError **error)
-{
-	gint32 i = 0;
-	GValue value = {0,};
-
-	if (_nm_object_get_property (object, interface, prop_name, &value, error)) {
-		i = g_value_get_int (&value);
-		g_value_unset (&value);
-	}
-
-	return i;
-}
-
-guint32
-_nm_object_get_uint_property (NMObject *object,
-                              const char *interface,
-                              const char *prop_name,
-                              GError **error)
-{
-	guint32 i = 0;
-	GValue value = {0,};
-
-	if (_nm_object_get_property (object, interface, prop_name, &value, error)) {
-		i = g_value_get_uint (&value);
-		g_value_unset (&value);
-	}
-
-	return i;
-}
-
-gboolean
-_nm_object_get_boolean_property (NMObject *object,
-                                 const char *interface,
-                                 const char *prop_name,
-                                 GError **error)
-{
-	gboolean b = FALSE;
-	GValue value = {0,};
-
-	if (_nm_object_get_property (object, interface, prop_name, &value, error)) {
-		b = g_value_get_boolean (&value);
-		g_value_unset (&value);
-	}
-
-	return b;
-}
-
-gint8
-_nm_object_get_byte_property (NMObject *object,
-                              const char *interface,
-                              const char *prop_name,
-                              GError **error)
-{
-	gint8 b = G_MAXINT8;
-	GValue value = {0,};
-
-	if (_nm_object_get_property (object, interface, prop_name, &value, error)) {
-		b = g_value_get_uchar (&value);
-		g_value_unset (&value);
-	}
-
-	return b;
-}
-
-gdouble
-_nm_object_get_double_property (NMObject *object,
-                                const char *interface,
-                                const char *prop_name,
-                                GError **error)
-{
-	gdouble d = G_MAXDOUBLE;
-	GValue value = {0,};
-
-	if (_nm_object_get_property (object, interface, prop_name, &value, error)) {
-		d = g_value_get_double (&value);
-		g_value_unset (&value);
-	}
-
-	return d;
-}
-
-GByteArray *
-_nm_object_get_byte_array_property (NMObject *object,
-                                    const char *interface,
-                                    const char *prop_name,
-                                    GError **error)
-{
-	GByteArray *array = NULL;
-	GValue value = {0,};
-
-	if (_nm_object_get_property (object, interface, prop_name, &value, error)) {
-		GArray * tmp = g_value_get_boxed (&value);
-		int i;
-		unsigned char byte;
-
-		array = g_byte_array_sized_new (tmp->len);
-		for (i = 0; i < tmp->len; i++) {
-			byte = g_array_index (tmp, unsigned char, i);
-			g_byte_array_append (array, &byte, 1);
-		}
-		g_value_unset (&value);
-	}
-
-	return array;
-}
diff --git a/libnm-glib/nm-vpn-connection.c b/libnm-glib/nm-vpn-connection.c
index 94d4110..58c2ea4 100644
--- a/libnm-glib/nm-vpn-connection.c
+++ b/libnm-glib/nm-vpn-connection.c
@@ -99,21 +99,11 @@ nm_vpn_connection_get_banner (NMVPNConnection *vpn)
 	priv = NM_VPN_CONNECTION_GET_PRIVATE (vpn);
 
 	/* We need to update vpn_state first in case it's unknown. */
-	nm_vpn_connection_get_vpn_state (vpn);
+	_nm_object_ensure_inited (NM_OBJECT (vpn));
 
 	if (priv->vpn_state != NM_VPN_CONNECTION_STATE_ACTIVATED)
 		return NULL;
 
-	if (!priv->banner) {
-		priv->banner = _nm_object_get_string_property (NM_OBJECT (vpn),
-		                                               NM_DBUS_INTERFACE_VPN_CONNECTION,
-		                                               DBUS_PROP_BANNER,
-		                                               NULL);
-		if (priv->banner && !strlen (priv->banner)) {
-			g_free (priv->banner);
-			priv->banner = NULL;
-		}
-	}
 	return priv->banner;
 }
 
@@ -128,18 +118,10 @@ nm_vpn_connection_get_banner (NMVPNConnection *vpn)
 NMVPNConnectionState
 nm_vpn_connection_get_vpn_state (NMVPNConnection *vpn)
 {
-	NMVPNConnectionPrivate *priv;
-
 	g_return_val_if_fail (NM_IS_VPN_CONNECTION (vpn), NM_VPN_CONNECTION_STATE_UNKNOWN);
 
-	priv = NM_VPN_CONNECTION_GET_PRIVATE (vpn);
-	if (priv->vpn_state == NM_VPN_CONNECTION_STATE_UNKNOWN) {
-		priv->vpn_state = _nm_object_get_uint_property (NM_OBJECT (vpn),
-		                                                NM_DBUS_INTERFACE_VPN_CONNECTION,
-		                                                DBUS_PROP_VPN_STATE,
-		                                                NULL);
-	}
-	return priv->vpn_state;
+	_nm_object_ensure_inited (NM_OBJECT (vpn));
+	return NM_VPN_CONNECTION_GET_PRIVATE (vpn)->vpn_state;
 }
 
 static void
diff --git a/libnm-glib/nm-wimax-nsp.c b/libnm-glib/nm-wimax-nsp.c
index a4f1ea8..bfacc87 100644
--- a/libnm-glib/nm-wimax-nsp.c
+++ b/libnm-glib/nm-wimax-nsp.c
@@ -90,18 +90,10 @@ nm_wimax_nsp_new (DBusGConnection *connection, const char *path)
 const char *
 nm_wimax_nsp_get_name (NMWimaxNsp *nsp)
 {
-	NMWimaxNspPrivate *priv;
-
 	g_return_val_if_fail (NM_IS_WIMAX_NSP (nsp), NULL);
 
-	priv = NM_WIMAX_NSP_GET_PRIVATE (nsp);
-	if (!priv->name)
-		priv->name = _nm_object_get_string_property (NM_OBJECT (nsp),
-		                                             NM_DBUS_INTERFACE_WIMAX_NSP,
-		                                             DBUS_PROP_NAME,
-		                                             NULL);
-
-	return priv->name;
+	_nm_object_ensure_inited (NM_OBJECT (nsp));
+	return NM_WIMAX_NSP_GET_PRIVATE (nsp)->name;
 }
 
 /**
@@ -115,19 +107,10 @@ nm_wimax_nsp_get_name (NMWimaxNsp *nsp)
 guint32
 nm_wimax_nsp_get_signal_quality (NMWimaxNsp *nsp)
 {
-	NMWimaxNspPrivate *priv;
-
 	g_return_val_if_fail (NM_IS_WIMAX_NSP (nsp), 0);
 
-	priv = NM_WIMAX_NSP_GET_PRIVATE (nsp);
-	if (!priv->signal_quality) {
-		priv->signal_quality = _nm_object_get_uint_property (NM_OBJECT (nsp),
-		                                                     NM_DBUS_INTERFACE_WIMAX_NSP,
-		                                                     DBUS_PROP_SIGNAL_QUALITY,
-		                                                     NULL);
-	}
-
-	return priv->signal_quality;
+	_nm_object_ensure_inited (NM_OBJECT (nsp));
+	return NM_WIMAX_NSP_GET_PRIVATE (nsp)->signal_quality;
 }
 
 /**
@@ -141,19 +124,10 @@ nm_wimax_nsp_get_signal_quality (NMWimaxNsp *nsp)
 NMWimaxNspNetworkType
 nm_wimax_nsp_get_network_type (NMWimaxNsp *nsp)
 {
-	NMWimaxNspPrivate *priv;
-
 	g_return_val_if_fail (NM_IS_WIMAX_NSP (nsp), NM_WIMAX_NSP_NETWORK_TYPE_UNKNOWN);
 
-	priv = NM_WIMAX_NSP_GET_PRIVATE (nsp);
-	if (!priv->network_type) {
-		priv->network_type = _nm_object_get_uint_property (NM_OBJECT (nsp),
-		                                                   NM_DBUS_INTERFACE_WIMAX_NSP,
-		                                                   DBUS_PROP_NETWORK_TYPE,
-		                                                   NULL);
-	}
-
-	return priv->network_type;
+	_nm_object_ensure_inited (NM_OBJECT (nsp));
+	return NM_WIMAX_NSP_GET_PRIVATE (nsp)->network_type;
 }
 
 /**
-- 
1.7.7.5

>From face59fa8bfc67421c898b0a3a71d424c05c3df0 Mon Sep 17 00:00:00 2001
From: Dan Winship <danw gnome org>
Date: Wed, 11 Jan 2012 07:56:04 -0500
Subject: [PATCH 08/12] 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.
---
 libnm-glib/nm-active-connection.c |  131 +++++++++++--
 libnm-glib/nm-client.c            |   58 +------
 libnm-glib/nm-device-private.h    |    4 -
 libnm-glib/nm-device-wifi.c       |   38 +----
 libnm-glib/nm-device-wimax.c      |   38 +----
 libnm-glib/nm-device.c            |  373 +++++++++++++++----------------------
 libnm-glib/nm-object-private.h    |   10 +
 libnm-glib/nm-object.c            |  256 ++++++++++++++++++++++++--
 8 files changed, 517 insertions(+), 391 deletions(-)

diff --git a/libnm-glib/nm-active-connection.c b/libnm-glib/nm-active-connection.c
index a68da56..0c922b7 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 b46e0df..edbfe8d 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 2c56a0e..5abf03f 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 91106d3..ca0dfba 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 d9555a3..e464dd9 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 208f415..616f110 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 7b14ad6..08aa525 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 5eb7a0a..dfcb33f 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);
 }
 
-- 
1.7.7.5

>From 1f7dc2f1c03a120c16700a4f7f5d2155ba304c7e Mon Sep 17 00:00:00 2001
From: Dan Winship <danw gnome org>
Date: Tue, 10 Jan 2012 12:38:19 -0500
Subject: [PATCH 09/12] 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.
---
 libnm-glib/nm-client.c         |   90 ++++-----------------
 libnm-glib/nm-device-wifi.c    |  105 +++++-------------------
 libnm-glib/nm-device-wimax.c   |  101 +++++------------------
 libnm-glib/nm-object-private.h |   11 +++
 libnm-glib/nm-object.c         |  176 ++++++++++++++++++++++++++++++++++++++++
 5 files changed, 247 insertions(+), 236 deletions(-)

diff --git a/libnm-glib/nm-client.c b/libnm-glib/nm-client.c
index edbfe8d..1178dbb 100644
--- a/libnm-glib/nm-client.c
+++ b/libnm-glib/nm-client.c
@@ -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,
diff --git a/libnm-glib/nm-device-wifi.c b/libnm-glib/nm-device-wifi.c
index ca0dfba..4c9c6be 100644
--- a/libnm-glib/nm-device-wifi.c
+++ b/libnm-glib/nm-device-wifi.c
@@ -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);
-
-	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);
-		}
+	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);
 
-		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),
diff --git a/libnm-glib/nm-device-wimax.c b/libnm-glib/nm-device-wimax.c
index e464dd9..2eb8846 100644
--- a/libnm-glib/nm-device-wimax.c
+++ b/libnm-glib/nm-device-wimax.c
@@ -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;
-
-	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);
-		}
+	NMWimaxNsp *nsp = NM_WIMAX_NSP (nsp_obj);
 
-		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,
diff --git a/libnm-glib/nm-object-private.h b/libnm-glib/nm-object-private.h
index 08aa525..83cd82f 100644
--- a/libnm-glib/nm-object-private.h
+++ b/libnm-glib/nm-object-private.h
@@ -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 */
diff --git a/libnm-glib/nm-object.c b/libnm-glib/nm-object.c
index dfcb33f..58efe06 100644
--- a/libnm-glib/nm-object.c
+++ b/libnm-glib/nm-object.c
@@ -48,11 +48,23 @@ typedef struct {
 } 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);
+}
-- 
1.7.7.5



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]