[gnome-control-center] network: keep the network UI updated as devices are added, removed or changed



commit d7a8e5670a89f4614a6219357440c006ee745d2f
Author: Richard Hughes <richard hughsie com>
Date:   Thu Dec 16 10:33:38 2010 +0000

    network: keep the network UI updated as devices are added, removed or changed
    
    Note: I've found some NetworkManager bugs in this, as 'dbus-monitor --system' will
    verify the missing signals from the daemon.

 panels/network/cc-network-panel.c |  344 ++++++++++++++++++++++++-------------
 1 files changed, 225 insertions(+), 119 deletions(-)
---
diff --git a/panels/network/cc-network-panel.c b/panels/network/cc-network-panel.c
index e099688..32daca4 100644
--- a/panels/network/cc-network-panel.c
+++ b/panels/network/cc-network-panel.c
@@ -33,12 +33,35 @@ G_DEFINE_DYNAMIC_TYPE (CcNetworkPanel, cc_network_panel, CC_TYPE_PANEL)
 
 struct _CcNetworkPanelPrivate
 {
-	GSettings	*proxy_settings;
 	GCancellable	*cancellable;
-	GtkBuilder	*builder;
+	gchar		*current_device;
 	GDBusProxy	*proxy;
+	GPtrArray	*devices;
+	GSettings	*proxy_settings;
+	GtkBuilder	*builder;
 };
 
+
+typedef struct {
+	CcNetworkPanel	*panel;
+	gchar		*active_access_point;
+	gchar		*device_id;
+	gchar		*modem_imei;
+	gchar		*operator_name;
+	gchar		*udi;
+	GDBusProxy	*proxy;
+	GDBusProxy	*proxy_additional;
+	guint		 type;
+} PanelDeviceItem;
+
+typedef struct {
+	gchar		*access_point;
+	gchar		*active_access_point;
+	guint		 strength;
+	guint		 mode;
+	CcNetworkPanel	*panel;
+} PanelAccessPointItem;
+
 enum {
 	PANEL_DEVICES_COLUMN_ICON,
 	PANEL_DEVICES_COLUMN_TITLE,
@@ -58,6 +81,8 @@ enum {
 	PANEL_WIRELESS_COLUMN_LAST
 };
 
+static void	panel_device_refresh_item_ui		(PanelDeviceItem *item);
+
 static void
 cc_network_panel_get_property (GObject    *object,
 			       guint       property_id,
@@ -92,6 +117,7 @@ cc_network_panel_dispose (GObject *object)
 		priv->proxy_settings = NULL;
 	}
 	if (priv->cancellable != NULL) {
+		g_cancellable_cancel (priv->cancellable);
 		g_object_unref (priv->cancellable);
 		priv->cancellable = NULL;
 	}
@@ -111,7 +137,10 @@ static void
 cc_network_panel_finalize (GObject *object)
 {
 	CcNetworkPanelPrivate *priv = CC_NETWORK_PANEL (object)->priv;
-	g_cancellable_cancel (priv->cancellable);
+
+	g_free (priv->current_device);
+	g_ptr_array_unref (priv->devices);
+
 	G_OBJECT_CLASS (cc_network_panel_parent_class)->finalize (object);
 }
 
@@ -232,46 +261,6 @@ panel_set_value_for_combo (CcNetworkPanel *panel, GtkComboBox *combo_box, gint v
 	panel_proxy_mode_combo_setup_widgets (panel, value);
 }
 
-/**
- * panel_refresh:
- **/
-static void
-panel_refresh (CcNetworkPanelPrivate *priv)
-{
-	return;
-}
-
-/**
- * panel_dbus_signal_cb:
- **/
-static void
-panel_dbus_signal_cb (GDBusProxy *proxy,
-		   gchar      *sender_name,
-		   gchar      *signal_name,
-		   GVariant   *parameters,
-		   gpointer    user_data)
-{
-//	CcNetworkPanelPrivate *priv = CC_NETWORK_PANEL (user_data)->priv;
-
-	/* get the new state */
-	if (g_strcmp0 (signal_name, "StateChanged") == 0) {
-		g_debug ("ensure devices are correct");
-		return;
-	}
-}
-
-typedef struct {
-	CcNetworkPanel		*panel;
-	gchar			*active_access_point;
-	gchar			*device_id;
-	gchar			*modem_imei;
-	gchar			*operator_name;
-	gchar			*udi;
-	GDBusProxy		*proxy;
-	GDBusProxy		*proxy_additional;
-	guint			 type;
-} PanelDeviceItem;
-
 static void
 panel_free_device_item (PanelDeviceItem *item)
 {
@@ -319,14 +308,6 @@ panel_add_device_to_listview (PanelDeviceItem *item)
 	g_free (title);
 }
 
-typedef struct {
-	gchar		*access_point;
-	gchar		*active_access_point;
-	guint		 strength;
-	guint		 mode;
-	CcNetworkPanel	*panel;
-} PanelAccessPointItem;
-
 /**
  * panel_got_proxy_access_point_cb:
  **/
@@ -619,6 +600,24 @@ out:
 }
 
 /**
+ * panel_device_properties_changed_cb:
+ **/
+static void
+panel_device_properties_changed_cb (GDBusProxy *proxy,
+				    GVariant *changed_properties,
+				    const gchar* const *invalidated_properties,
+				    gpointer user_data)
+{
+	PanelDeviceItem *item = (PanelDeviceItem *) user_data;
+	CcNetworkPanelPrivate *priv = item->panel->priv;
+
+	/* only refresh the selected device */
+	if (g_strcmp0 (priv->current_device, item->device_id) == 0)
+		panel_device_refresh_item_ui (item);
+//xxx
+}
+
+/**
  * panel_got_device_proxy_cb:
  **/
 static void
@@ -628,7 +627,6 @@ panel_got_device_proxy_cb (GObject *source_object, GAsyncResult *res, gpointer u
 	GVariant *variant_type = NULL;
 	GVariant *variant_udi = NULL;
 	PanelDeviceItem *item = (PanelDeviceItem *) user_data;
-	CcNetworkPanelPrivate *priv = item->panel->priv;
 
 	item->proxy = g_dbus_proxy_new_for_bus_finish (res, &error);
 	if (item->proxy == NULL) {
@@ -687,6 +685,11 @@ panel_got_device_proxy_cb (GObject *source_object, GAsyncResult *res, gpointer u
 	} else {
 		panel_add_device_to_listview (item);
 	}
+
+	/* we want to update the UI */
+	g_signal_connect (item->proxy, "g-properties-changed",
+			  G_CALLBACK (panel_device_properties_changed_cb),
+			  item);
 out:
 	if (variant_udi != NULL)
 		g_variant_unref (variant_udi);
@@ -708,6 +711,9 @@ panel_add_device (CcNetworkPanel *panel, const gchar *device_id)
 	item->panel = g_object_ref (panel);
 	item->device_id = g_strdup (device_id);
 
+	/* add to array */
+	g_ptr_array_add (panel->priv->devices, item);
+
 	/* get initial device state */
 	g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM,
 				  G_DBUS_PROXY_FLAGS_NONE,
@@ -721,19 +727,61 @@ panel_add_device (CcNetworkPanel *panel, const gchar *device_id)
 }
 
 /**
+ * panel_remove_device:
+ **/
+static void
+panel_remove_device (CcNetworkPanel *panel, const gchar *device_id)
+{
+	gboolean ret;
+	gchar *id_tmp;
+	GtkTreeIter iter;
+	GtkTreeModel *model;
+	guint i;
+	PanelDeviceItem *item;
+
+	/* remove device from array */
+	for (i=0; i<panel->priv->devices->len; i++) {
+		item = g_ptr_array_index (panel->priv->devices, i);
+		if (g_strcmp0 (item->device_id, device_id) == 0) {
+			g_ptr_array_remove_index_fast (panel->priv->devices, i);
+			break;
+		}
+	}
+
+	/* remove device from model */
+	model = GTK_TREE_MODEL (gtk_builder_get_object (panel->priv->builder,
+							"liststore_devices"));
+	ret = gtk_tree_model_get_iter_first (model, &iter);
+	if (!ret)
+		return;
+
+	/* get the other elements */
+	do {
+		gtk_tree_model_get (model, &iter,
+				    PANEL_DEVICES_COLUMN_ID, &id_tmp,
+				    -1);
+		if (g_strcmp0 (id_tmp, device_id) == 0) {
+			gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
+			g_free (id_tmp);
+			break;
+		}
+		g_free (id_tmp);
+	} while (gtk_tree_model_iter_next (model, &iter));
+}
+
+/**
  * panel_get_devices_cb:
  **/
 static void
 panel_get_devices_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
 {
 	CcNetworkPanel *panel = CC_NETWORK_PANEL (user_data);
-//	CcNetworkPanelPrivate *priv = panel->priv;
 	const gchar *object_path;
 	GError *error = NULL;
 	gsize len;
 	GVariantIter iter;
+	GVariant *child;
 	GVariant *result;
-	GVariant *test;
 
 	result = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object), res, &error);
 	if (result == NULL) {
@@ -742,8 +790,8 @@ panel_get_devices_cb (GObject *source_object, GAsyncResult *res, gpointer user_d
 		return;
 	}
 
-	test = g_variant_get_child_value (result, 0);
-	len = g_variant_iter_init (&iter, test);
+	child = g_variant_get_child_value (result, 0);
+	len = g_variant_iter_init (&iter, child);
 	if (len == 0) {
 		g_warning ("no devices?!");
 		goto out;
@@ -756,7 +804,44 @@ panel_get_devices_cb (GObject *source_object, GAsyncResult *res, gpointer user_d
 	}
 out:
 	g_variant_unref (result);
-	g_variant_unref (test);
+	g_variant_unref (child);
+}
+
+
+/**
+ * panel_dbus_manager_signal_cb:
+ **/
+static void
+panel_dbus_manager_signal_cb (GDBusProxy *proxy,
+			      gchar *sender_name,
+			      gchar *signal_name,
+			      GVariant *parameters,
+			      gpointer user_data)
+{
+	gchar *object_path = NULL;
+	CcNetworkPanel *panel = CC_NETWORK_PANEL (user_data);
+
+	/* get the new state */
+	if (g_strcmp0 (signal_name, "StateChanged") == 0) {
+		g_debug ("ensure devices are correct");
+		goto out;
+	}
+
+	/* device added or removed */
+	if (g_strcmp0 (signal_name, "DeviceAdded") == 0) {
+		g_variant_get (parameters, "(o)", &object_path);
+		panel_add_device (panel, object_path);
+		goto out;
+	}
+
+	/* device added or removed */
+	if (g_strcmp0 (signal_name, "DeviceRemoved") == 0) {
+		g_variant_get (parameters, "(o)", &object_path);
+		panel_remove_device (panel, object_path);
+		goto out;
+	}
+out:
+	g_free (object_path);
 }
 
 /**
@@ -766,7 +851,6 @@ static void
 panel_got_network_proxy_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
 {
 	GError *error = NULL;
-
 	CcNetworkPanelPrivate *priv = CC_NETWORK_PANEL (user_data)->priv;
 
 	priv->proxy = g_dbus_proxy_new_for_bus_finish (res, &error);
@@ -779,7 +863,7 @@ panel_got_network_proxy_cb (GObject *source_object, GAsyncResult *res, gpointer
 	/* we want to change the UI in reflection to device events */
 	g_signal_connect (priv->proxy,
 			  "g-signal",
-			  G_CALLBACK (panel_dbus_signal_cb),
+			  G_CALLBACK (panel_dbus_manager_signal_cb),
 			  user_data);
 
 	/* get the new state */
@@ -791,8 +875,6 @@ panel_got_network_proxy_cb (GObject *source_object, GAsyncResult *res, gpointer
 			   priv->cancellable,
 			   panel_get_devices_cb,
 			   user_data);
-
-	panel_refresh (priv);
 out:
 	return;
 }
@@ -909,28 +991,29 @@ panel_set_label_for_variant_ipv4 (GtkWidget *widget, GVariant *variant)
  * panel_populate_wired_device:
  **/
 static void
-panel_populate_wired_device (CcNetworkPanel *panel, PanelDeviceItem *item)
+panel_populate_wired_device (PanelDeviceItem *item)
 {
 	GtkWidget *widget;
 	GVariant *ip4;
 	GVariant *hw_address;
 	GVariant *speed;
+	CcNetworkPanelPrivate *priv = item->panel->priv;
 
 	/* set IP */
 	ip4 = g_dbus_proxy_get_cached_property (item->proxy, "Ip4Address");
-	widget = GTK_WIDGET (gtk_builder_get_object (panel->priv->builder,
+	widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
 						     "label_wired_ip"));
 	panel_set_label_for_variant_ipv4 (widget, ip4);
 
 	/* set MAC */
 	hw_address = g_dbus_proxy_get_cached_property (item->proxy_additional, "HwAddress");
-	widget = GTK_WIDGET (gtk_builder_get_object (panel->priv->builder,
+	widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
 						     "label_wired_mac"));
 	panel_set_label_for_variant_string (widget, hw_address);
 
 	/* set speed */
 	speed = g_dbus_proxy_get_cached_property (item->proxy_additional, "Speed");
-	widget = GTK_WIDGET (gtk_builder_get_object (panel->priv->builder,
+	widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
 						     "label_wired_speed"));
 	panel_set_label_for_variant_speed (widget, speed);
 
@@ -943,28 +1026,29 @@ panel_populate_wired_device (CcNetworkPanel *panel, PanelDeviceItem *item)
  * panel_populate_wireless_device:
  **/
 static void
-panel_populate_wireless_device (CcNetworkPanel *panel, PanelDeviceItem *item)
+panel_populate_wireless_device (PanelDeviceItem *item)
 {
 	GtkWidget *widget;
 	GVariant *bitrate;
 	GVariant *hw_address;
 	GVariant *ip4;
+	CcNetworkPanelPrivate *priv = item->panel->priv;
 
 	/* set IP */
 	ip4 = g_dbus_proxy_get_cached_property (item->proxy, "Ip4Address");
-	widget = GTK_WIDGET (gtk_builder_get_object (panel->priv->builder,
+	widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
 						     "label_wireless_ip"));
 	panel_set_label_for_variant_ipv4 (widget, ip4);
 
 	/* set MAC */
 	hw_address = g_dbus_proxy_get_cached_property (item->proxy_additional, "HwAddress");
-	widget = GTK_WIDGET (gtk_builder_get_object (panel->priv->builder,
+	widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
 						     "label_wireless_mac"));
 	panel_set_label_for_variant_string (widget, hw_address);
 
 	/* set speed */
 	bitrate = g_dbus_proxy_get_cached_property (item->proxy_additional, "Bitrate");
-	widget = GTK_WIDGET (gtk_builder_get_object (panel->priv->builder,
+	widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
 						     "label_wireless_speed"));
 	panel_set_label_for_variant_bitrate (widget, bitrate);
 
@@ -977,27 +1061,28 @@ panel_populate_wireless_device (CcNetworkPanel *panel, PanelDeviceItem *item)
  * panel_populate_mobilebb_device:
  **/
 static void
-panel_populate_mobilebb_device (CcNetworkPanel *panel, PanelDeviceItem *item)
+panel_populate_mobilebb_device (PanelDeviceItem *item)
 {
 	GtkWidget *widget;
 	GVariant *ip4;
+	CcNetworkPanelPrivate *priv = item->panel->priv;
 
 	/* set IP */
 	ip4 = g_dbus_proxy_get_cached_property (item->proxy, "Ip4Address");
-	widget = GTK_WIDGET (gtk_builder_get_object (panel->priv->builder,
+	widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
 						     "label_wireless_ip"));
 	panel_set_label_for_variant_ipv4 (widget, ip4);
 
 	/* use data from ModemManager */
-	widget = GTK_WIDGET (gtk_builder_get_object (panel->priv->builder,
+	widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
 						     "label_mobilebb_provider"));
 	gtk_label_set_text (GTK_LABEL (widget), item->operator_name);
-	widget = GTK_WIDGET (gtk_builder_get_object (panel->priv->builder,
+	widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
 						     "label_mobilebb_imei"));
 	gtk_label_set_text (GTK_LABEL (widget), item->modem_imei);
 
 	/* I'm not sure where to get this data from */
-	widget = GTK_WIDGET (gtk_builder_get_object (panel->priv->builder,
+	widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
 						     "hbox_mobilebb_speed"));
 	gtk_widget_set_visible (widget, FALSE);
 
@@ -1005,94 +1090,114 @@ panel_populate_mobilebb_device (CcNetworkPanel *panel, PanelDeviceItem *item)
 }
 
 /**
- * panel_devices_treeview_clicked_cb:
+ * panel_device_refresh_item_ui:
  **/
 static void
-panel_devices_treeview_clicked_cb (GtkTreeSelection *selection, CcNetworkPanel *panel)
+panel_device_refresh_item_ui (PanelDeviceItem *item)
 {
-	gchar *id = NULL;
-	PanelDeviceItem *item;
-	GtkTreeIter iter;
-	GtkTreeModel *model;
 	GtkWidget *widget;
 	guint state;
-	GVariant *variant_id = NULL;
-	GVariant *variant_state = NULL;
-
-	/* will only work in single or browse selection mode! */
-	if (!gtk_tree_selection_get_selected (selection, &model, &iter)) {
-		g_debug ("no row selected");
-		goto out;
-	}
-
-	/* get id */
-	gtk_tree_model_get (model, &iter,
-			    PANEL_DEVICES_COLUMN_ID, &id,
-			    PANEL_DEVICES_COLUMN_COMPOSITE_DEVICE, &item,
-			    -1);
-
-	/* this is the proxy settings device */
-	if (item == NULL) {
-		widget = GTK_WIDGET (gtk_builder_get_object (panel->priv->builder,
-							     "hbox_device_header"));
-		gtk_widget_set_visible (widget, FALSE);
-		widget = GTK_WIDGET (gtk_builder_get_object (panel->priv->builder,
-							     "notebook_types"));
-		gtk_notebook_set_current_page (GTK_NOTEBOOK (widget), 2);
-		goto out;
-	}
+	GVariant *variant_id;
+	GVariant *variant_state;
+	CcNetworkPanelPrivate *priv = item->panel->priv;
 
 	/* we have a new device */
-	g_debug ("selected device is: %s", id);
-	widget = GTK_WIDGET (gtk_builder_get_object (panel->priv->builder,
+	g_debug ("selected device is: %s", item->device_id);
+	widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
 						     "hbox_device_header"));
 	gtk_widget_set_visible (widget, TRUE);
 
 	variant_id = g_dbus_proxy_get_cached_property (item->proxy, "Interface");
-	g_variant_get (variant_id, "s", &id);
+//	g_variant_get (variant_id, "s", &interface);
 
 	variant_state = g_dbus_proxy_get_cached_property (item->proxy, "State");
 	g_variant_get (variant_state, "u", &state);
 
-	g_debug ("device %s type %i @ %s", id, item->type, item->udi);
+	g_debug ("device %s type %i @ %s", item->device_id, item->type, item->udi);
 
 	/* set device icon */
-	widget = GTK_WIDGET (gtk_builder_get_object (panel->priv->builder,
+	widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
 						     "image_device"));
 	gtk_image_set_from_icon_name (GTK_IMAGE (widget),
 				      panel_device_type_to_icon_name (item->type),
 				      GTK_ICON_SIZE_DIALOG);
 
 	/* set device kind */
-	widget = GTK_WIDGET (gtk_builder_get_object (panel->priv->builder,
+	widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
 						     "label_device"));
 	gtk_label_set_label (GTK_LABEL (widget),
 			     panel_device_type_to_localized_string (item->type));
 
 	/* set device state */
-	widget = GTK_WIDGET (gtk_builder_get_object (panel->priv->builder,
+	widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
 						     "label_status"));
 	gtk_label_set_label (GTK_LABEL (widget),
 			     panel_device_state_to_localized_string (state));
 
-	widget = GTK_WIDGET (gtk_builder_get_object (panel->priv->builder,
+	widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
 						     "notebook_types"));
 	if (item->type == NM_DEVICE_TYPE_ETHERNET) {
 		gtk_notebook_set_current_page (GTK_NOTEBOOK (widget), 0);
-		panel_populate_wired_device (panel, item);
+		panel_populate_wired_device (item);
 	} else if (item->type == NM_DEVICE_TYPE_WIFI) {
 		gtk_notebook_set_current_page (GTK_NOTEBOOK (widget), 1);
-		panel_populate_wireless_device (panel, item);
+		panel_populate_wireless_device (item);
 	} else if (item->type == NM_DEVICE_TYPE_GSM ||
 	           item->type == NM_DEVICE_TYPE_CDMA) {
 		gtk_notebook_set_current_page (GTK_NOTEBOOK (widget), 4);
-		panel_populate_mobilebb_device (panel, item);
+		panel_populate_mobilebb_device (item);
+	}
+
+	g_variant_unref (variant_state);
+	g_variant_unref (variant_id);
+}
+
+/**
+ * panel_devices_treeview_clicked_cb:
+ **/
+static void
+panel_devices_treeview_clicked_cb (GtkTreeSelection *selection, CcNetworkPanel *panel)
+{
+	GtkTreeIter iter;
+	GtkTreeModel *model;
+	GtkWidget *widget;
+	PanelDeviceItem *item;
+	CcNetworkPanelPrivate *priv = panel->priv;
+
+	/* will only work in single or browse selection mode! */
+	if (!gtk_tree_selection_get_selected (selection, &model, &iter)) {
+		g_debug ("no row selected");
+		goto out;
 	}
 
+	/* get id */
+	gtk_tree_model_get (model, &iter,
+			    PANEL_DEVICES_COLUMN_COMPOSITE_DEVICE, &item,
+			    -1);
+
+	/* this is the proxy settings device */
+	if (item == NULL) {
+		widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
+							     "hbox_device_header"));
+		gtk_widget_set_visible (widget, FALSE);
+		widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
+							     "notebook_types"));
+		gtk_notebook_set_current_page (GTK_NOTEBOOK (widget), 2);
+
+		/* save so we ignore */
+		g_free (priv->current_device);
+		priv->current_device = NULL;
+		goto out;
+	}
+
+	/* save so we can update */
+	g_free (priv->current_device);
+	priv->current_device = g_strdup (item->device_id);
+
+	/* refresh item */
+	panel_device_refresh_item_ui (item);
 out:
-	if (variant_id != NULL)
-		g_variant_unref (variant_id);
-	g_free (id);
+	return;
 }
 
 /**
@@ -1155,6 +1260,7 @@ cc_network_panel_init (CcNetworkPanel *panel)
 	}
 
 	panel->priv->cancellable = g_cancellable_new ();
+	panel->priv->devices = g_ptr_array_new_with_free_func ((GDestroyNotify )panel_free_device_item);
 
 	/* get initial icon state */
 	g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM,



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