[network-manager-netbook] Add device handlers to keep the lists sync with NM data.



commit 326d88e41671ecfd47ccd78b6607596d54c3e3b4
Author: Tambet Ingo <tambet gmail com>
Date:   Mon May 25 17:36:11 2009 +0300

    Add device handlers to keep the lists sync with NM data.
    
    There was previously no place to handle device specific events. Things like
    "AP appears/disappears in scan list for existing connection" and carrier state
    changes for ethernet device, etc did not work correctly before. With the new
    layer between list and items, there's now a place to do these device type
    specific things.
---
 src/Makefile.am            |    8 ++
 src/nmn-device-handler.c   |  301 ++++++++++++++++++++++++++++++++++++++++++++
 src/nmn-device-handler.h   |   55 ++++++++
 src/nmn-ethernet-handler.c |  132 +++++++++++++++++++
 src/nmn-ethernet-handler.h |   30 +++++
 src/nmn-ethernet-item.c    |  115 ++++++------------
 src/nmn-ethernet-item.h    |    6 +-
 src/nmn-networks.c         |  190 ++++++++++------------------
 src/nmn-serial-handler.c   |   53 ++++++++
 src/nmn-serial-handler.h   |   30 +++++
 src/nmn-serial-item.c      |   97 ++++++---------
 src/nmn-serial-item.h      |    6 +-
 src/nmn-wifi-handler.c     |  253 +++++++++++++++++++++++++++++++++++++
 src/nmn-wifi-handler.h     |   30 +++++
 src/nmn-wifi-item.c        |   41 +++++--
 src/nmn-wifi-item.h        |    3 +
 16 files changed, 1073 insertions(+), 277 deletions(-)

diff --git a/src/Makefile.am b/src/Makefile.am
index 6c628e5..529e470 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -20,6 +20,10 @@ network_manager_netbook_LDADD = \
 network_manager_netbook_SOURCES = \
 	nmn-applet.c \
 	nmn-applet.h \
+	nmn-device-handler.c \
+	nmn-device-handler.h \
+	nmn-ethernet-handler.c \
+	nmn-ethernet-handler.h \
 	nmn-ethernet-item.c \
 	nmn-ethernet-item.h \
 	nmn-icon-cache.c \
@@ -40,10 +44,14 @@ network_manager_netbook_SOURCES = \
 	nmn-nm-data.h \
 	nmn-plug.c \
 	nmn-plug.h \
+	nmn-serial-handler.c \
+	nmn-serial-handler.h \
 	nmn-serial-item.c \
 	nmn-serial-item.h \
 	nmn-status-icon.c \
 	nmn-status-icon.h \
+	nmn-wifi-handler.c \
+	nmn-wifi-handler.h \
 	nmn-wifi-item.c \
 	nmn-wifi-item.h \
 	nmn-wifi-list.c \
diff --git a/src/nmn-device-handler.c b/src/nmn-device-handler.c
new file mode 100644
index 0000000..846da22
--- /dev/null
+++ b/src/nmn-device-handler.c
@@ -0,0 +1,301 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+#include "nmn-device-handler.h"
+#include "nmn-network-item.h"
+
+G_DEFINE_TYPE (NmnDeviceHandler, nmn_device_handler, G_TYPE_OBJECT)
+
+enum {
+    PROP_0,
+    PROP_NM_DATA,
+    PROP_DEVICE,
+
+    LAST_PROP
+};
+
+enum {
+    ITEM_ADDED,
+    LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL];
+
+#define GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), NMN_TYPE_DEVICE_HANDLER, NmnDeviceHandlerPrivate))
+
+typedef struct {
+    NmnNMData *nm_data;
+    NMDevice *device;
+    GSList *items;
+    gboolean started;
+
+    gboolean disposed;
+} NmnDeviceHandlerPrivate;
+
+static void
+connection_added (NMSettings *settings,
+                  NMExportedConnection *exported,
+                  gpointer user_data)
+{
+    NmnDeviceHandler *handler = NMN_DEVICE_HANDLER (user_data);
+
+    if (NMN_DEVICE_HANDLER_GET_CLASS (handler)->connection_added)
+        NMN_DEVICE_HANDLER_GET_CLASS (handler)->connection_added (handler, exported);
+}
+
+static void
+add_one_connection (gpointer data, gpointer user_data)
+{
+    connection_added (NULL, NM_EXPORTED_CONNECTION (data), user_data);
+}
+
+void
+nmn_device_handler_start (NmnDeviceHandler *self)
+{
+    NMSettings *settings;
+    NmnDeviceHandlerPrivate *priv;
+    GSList *list;
+
+    g_return_if_fail (NMN_IS_DEVICE_HANDLER (self));
+
+    priv = GET_PRIVATE (self);
+    if (priv->started)
+        return;
+
+    priv->started = TRUE;
+
+    settings = nmn_nm_data_get_user_settings (priv->nm_data);
+    if (settings) {
+        g_signal_connect (settings, "new-connection", G_CALLBACK (connection_added), self);
+
+        list = nm_settings_list_connections (settings);
+        g_slist_foreach (list, add_one_connection, self);
+        g_slist_free (list);
+    }
+
+    settings = nmn_nm_data_get_system_settings (priv->nm_data);
+    if (settings) {
+        g_signal_connect (settings, "new-connection", G_CALLBACK (connection_added), self);
+
+        list = nm_settings_list_connections (settings);
+        g_slist_foreach (list, add_one_connection, self);
+        g_slist_free (list);
+    }
+}
+
+NmnNMData *
+nmn_device_handler_get_nm_data (NmnDeviceHandler *self)
+{
+    g_return_val_if_fail (NMN_IS_DEVICE_HANDLER (self), NULL);
+
+    return GET_PRIVATE (self)->nm_data;
+}
+
+NMDevice *
+nmn_device_handler_get_device (NmnDeviceHandler *self)
+{
+    g_return_val_if_fail (NMN_IS_DEVICE_HANDLER (self), NULL);
+
+    return GET_PRIVATE (self)->device;
+}
+
+static void
+item_removed (NmnItem *item, gpointer user_data)
+{
+    NmnDeviceHandlerPrivate *priv = GET_PRIVATE (user_data);
+
+    priv->items = g_slist_remove (priv->items, item);
+}
+
+void
+nmn_device_handler_add_item (NmnDeviceHandler *self,
+                             NmnItem *item)
+{
+    NmnDeviceHandlerPrivate *priv;
+
+    g_return_if_fail (NMN_IS_DEVICE_HANDLER (self));
+    g_return_if_fail (NMN_IS_ITEM (item));
+
+    g_signal_connect (item, "remove-requested", G_CALLBACK (item_removed), self);
+
+    priv = GET_PRIVATE (self);
+    priv->items = g_slist_prepend (priv->items, item);
+    g_signal_emit (self, signals[ITEM_ADDED], 0, item);
+}
+
+GSList *
+nmn_device_handler_get_items (NmnDeviceHandler *self)
+{
+    g_return_val_if_fail (NMN_IS_DEVICE_HANDLER (self), NULL);
+
+    return GET_PRIVATE (self)->items;
+}
+
+GSList *
+nmn_device_handler_get_connections (NmnDeviceHandler *self)
+{
+    NmnDeviceHandlerPrivate *priv;
+    NMSettings *settings;
+    GSList *list = NULL;
+
+    g_return_val_if_fail (NMN_IS_DEVICE_HANDLER (self), NULL);
+
+    priv = GET_PRIVATE (self);
+
+    settings = nmn_nm_data_get_user_settings (priv->nm_data);
+    if (settings)
+        list = nm_settings_list_connections (settings);
+
+    settings = nmn_nm_data_get_system_settings (priv->nm_data);
+    if (settings)
+        list = g_slist_concat (list, nm_settings_list_connections (settings));
+
+    return list;
+}
+
+NmnItem *
+nmn_device_handler_get_item_for_connection (NmnDeviceHandler *self,
+                                            NMExportedConnection *connection)
+{
+    GSList *list;
+    GSList *iter;
+
+    g_return_val_if_fail (NMN_IS_DEVICE_HANDLER (self), NULL);
+    g_return_val_if_fail (NM_IS_EXPORTED_CONNECTION (connection), NULL);
+
+    list = GET_PRIVATE (self)->items;
+    for (iter = list; iter; iter = iter->next) {
+        if (nmn_network_item_get_connection (NMN_NETWORK_ITEM (iter->data)) == connection)
+            return NMN_ITEM (iter->data);
+    }
+
+    return NULL;
+}
+
+static void
+nmn_device_handler_init (NmnDeviceHandler *handler)
+{
+}
+
+static GObject*
+constructor (GType type,
+             guint n_construct_params,
+             GObjectConstructParam *construct_params)
+{
+    GObject *object;
+    NmnDeviceHandlerPrivate *priv;
+
+    object = G_OBJECT_CLASS (nmn_device_handler_parent_class)->constructor
+        (type, n_construct_params, construct_params);
+
+    if (!object)
+        return NULL;
+
+    priv = GET_PRIVATE (object);
+
+    if (!priv->nm_data || !priv->device) {
+        g_warning ("Missing constructor arguments");
+        g_object_unref (object);
+        return NULL;
+    }
+
+    return object;
+}
+
+static void
+set_property (GObject *object, guint prop_id,
+              const GValue *value, GParamSpec *pspec)
+{
+    NmnDeviceHandlerPrivate *priv = GET_PRIVATE (object);
+
+    switch (prop_id) {
+    case PROP_NM_DATA:
+        /* Construct only */
+        priv->nm_data = g_value_dup_object (value);
+        break;
+    case PROP_DEVICE:
+        /* Construct only */
+        priv->device = g_value_dup_object (value);
+        break;
+    default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+        break;
+    }
+}
+
+static void
+get_property (GObject *object, guint prop_id,
+              GValue *value, GParamSpec *pspec)
+{
+    NmnDeviceHandlerPrivate *priv = GET_PRIVATE (object);
+
+    switch (prop_id) {
+    case PROP_NM_DATA:
+        g_value_set_object (value, priv->nm_data);
+        break;
+    case PROP_DEVICE:
+        g_value_set_object (value, priv->device);
+        break;
+    default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+        break;
+    }
+}
+
+static void
+dispose (GObject *object)
+{
+    NmnDeviceHandlerPrivate *priv = GET_PRIVATE (object);
+
+    if (priv->disposed)
+        return;
+
+    g_slist_foreach (priv->items, (GFunc) g_object_unref, NULL);
+    g_slist_free (priv->items);
+
+    g_object_unref (priv->device);
+    g_object_unref (priv->nm_data);
+    priv->disposed = TRUE;
+
+    G_OBJECT_CLASS (nmn_device_handler_parent_class)->dispose (object);
+}
+
+static void
+nmn_device_handler_class_init (NmnDeviceHandlerClass *class)
+{
+    GObjectClass *object_class = G_OBJECT_CLASS (class);
+
+    g_type_class_add_private (object_class, sizeof (NmnDeviceHandlerPrivate));
+
+    object_class->constructor = constructor;
+    object_class->set_property = set_property;
+    object_class->get_property = get_property;
+    object_class->dispose = dispose;
+
+    /* properties */
+    g_object_class_install_property
+        (object_class, PROP_NM_DATA,
+         g_param_spec_object (NMN_DEVICE_HANDLER_NM_DATA,
+                              "NmnNMData",
+                              "NmnNMData",
+                              NMN_TYPE_NM_DATA,
+                              G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+    g_object_class_install_property
+        (object_class, PROP_DEVICE,
+         g_param_spec_object (NMN_DEVICE_HANDLER_DEVICE,
+                              "NMDevice",
+                              "NMDevice",
+                              NM_TYPE_DEVICE,
+                              G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+    /* signals */
+    signals[ITEM_ADDED] = g_signal_new 
+        ("item-added",
+         G_OBJECT_CLASS_TYPE (class),
+         G_SIGNAL_RUN_LAST,
+         G_STRUCT_OFFSET (NmnDeviceHandlerClass, item_added),
+         NULL, NULL,
+         g_cclosure_marshal_VOID__OBJECT,
+         G_TYPE_NONE, 1,
+         NMN_TYPE_ITEM);
+}
diff --git a/src/nmn-device-handler.h b/src/nmn-device-handler.h
new file mode 100644
index 0000000..46ce72c
--- /dev/null
+++ b/src/nmn-device-handler.h
@@ -0,0 +1,55 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+#ifndef NMN_DEVICE_HANDLER_H
+#define NMN_DEVICE_HANDLER_H
+
+#include <glib-object.h>
+#include <nm-device.h>
+#include <nm-settings.h>
+#include "nmn-nm-data.h"
+#include "nmn-item.h"
+
+#define NMN_TYPE_DEVICE_HANDLER            (nmn_device_handler_get_type ())
+#define NMN_DEVICE_HANDLER(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMN_TYPE_DEVICE_HANDLER, NmnDeviceHandler))
+#define NMN_DEVICE_HANDLER_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), NMN_TYPE_DEVICE_HANDLER, NmnDeviceHandlerClass))
+#define NMN_IS_DEVICE_HANDLER(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMN_TYPE_DEVICE_HANDLER))
+#define NMN_IS_DEVICE_HANDLER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NMN_TYPE_DEVICE_HANDLER))
+#define NMN_DEVICE_HANDLER_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NMN_TYPE_DEVICE_HANDLER, NmnDeviceHandlerClass))
+
+#define NMN_DEVICE_HANDLER_NM_DATA "nm-data"
+#define NMN_DEVICE_HANDLER_DEVICE "device"
+
+typedef struct {
+    GObject parent;
+} NmnDeviceHandler;
+
+typedef struct {
+    GObjectClass parent;
+
+    /* methods */
+    void (*connection_added) (NmnDeviceHandler *self,
+                              NMExportedConnection *exported);
+
+    /* signals */
+    void (*item_added) (NmnDeviceHandler *self,
+                        NmnItem *item);
+} NmnDeviceHandlerClass;
+
+GType nmn_device_handler_get_type (void);
+
+void nmn_device_handler_start (NmnDeviceHandler *self);
+
+NmnNMData *nmn_device_handler_get_nm_data (NmnDeviceHandler *self);
+NMDevice *nmn_device_handler_get_device (NmnDeviceHandler *self);
+
+void nmn_device_handler_add_item (NmnDeviceHandler *self,
+                                  NmnItem *item);
+
+GSList *nmn_device_handler_get_items (NmnDeviceHandler *self);
+GSList *nmn_device_handler_get_connections (NmnDeviceHandler *self);
+
+NmnItem *nmn_device_handler_get_item_for_connection (NmnDeviceHandler *self,
+                                                     NMExportedConnection *connection);
+
+
+#endif /* NMN_DEVICE_HANDLER_H */
diff --git a/src/nmn-ethernet-handler.c b/src/nmn-ethernet-handler.c
new file mode 100644
index 0000000..bd2b00a
--- /dev/null
+++ b/src/nmn-ethernet-handler.c
@@ -0,0 +1,132 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+#include <string.h>
+#include <nm-settings.h>
+#include "nmn-ethernet-handler.h"
+#include "nmn-ethernet-item.h"
+#include "utils.h"
+
+G_DEFINE_TYPE (NmnEthernetHandler, nmn_ethernet_handler, NMN_TYPE_DEVICE_HANDLER)
+
+#define GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), NMN_TYPE_ETHERNET_HANDLER, NmnEthernetHandlerPrivate))
+
+typedef struct {
+    gulong carrier_changed_id;
+
+    gboolean disposed;
+} NmnEthernetHandlerPrivate;
+
+NmnDeviceHandler *
+nmn_ethernet_handler_new (NmnNMData *nm_data,
+                          NMDeviceEthernet *device)
+{
+    g_return_val_if_fail (NMN_IS_NM_DATA (nm_data), NULL);
+    g_return_val_if_fail (NM_IS_DEVICE_ETHERNET (device), NULL);
+
+    return NMN_DEVICE_HANDLER (g_object_new (NMN_TYPE_ETHERNET_HANDLER,
+                                             NMN_DEVICE_HANDLER_NM_DATA, nm_data,
+                                             NMN_DEVICE_HANDLER_DEVICE, device,
+                                             NULL));
+}
+
+static void
+connection_added (NmnDeviceHandler *handler,
+                  NMExportedConnection *exported)
+{
+    NMConnection *wrapped;
+    NMDeviceEthernet *device;
+    GtkWidget *item;
+
+    device = NM_DEVICE_ETHERNET (nmn_device_handler_get_device (handler));
+    if (!nm_device_ethernet_get_carrier (device))
+        return;
+
+    wrapped = nm_exported_connection_get_connection (exported);
+    if (utils_connection_valid_for_device (wrapped, NM_DEVICE (device), NULL)) {
+        item = nmn_ethernet_item_new (nmn_device_handler_get_nm_data (handler), device);
+        g_object_set (item, NMN_NETWORK_ITEM_CONNECTION, exported, NULL);
+        nmn_device_handler_add_item (handler, NMN_ITEM (item));
+    }
+}
+
+static void
+carrier_changed (NMDeviceEthernet *device,
+                 GParamSpec *pspec,
+                 gpointer user_data)
+{
+    NmnDeviceHandler *handler = NMN_DEVICE_HANDLER (user_data);
+    GSList *list;
+    GSList *iter;
+
+    if (nm_device_ethernet_get_carrier (device)) {
+        list = nmn_device_handler_get_connections (handler);
+        for (iter = list; iter; iter = iter->next)
+            connection_added (handler, NM_EXPORTED_CONNECTION (iter->data));
+
+        g_slist_free (list);
+    } else {
+        list = nmn_device_handler_get_items (handler);
+        for (iter = list; iter; iter = iter->next)
+            nmn_item_remove_request (NMN_ITEM (iter->data));
+    }
+}
+
+static GObject*
+constructor (GType type,
+             guint n_construct_params,
+             GObjectConstructParam *construct_params)
+{
+    GObject *object;
+    NMDeviceEthernet *device;
+    NmnEthernetHandlerPrivate *priv;
+
+    object = G_OBJECT_CLASS (nmn_ethernet_handler_parent_class)->constructor
+        (type, n_construct_params, construct_params);
+
+    if (!object)
+        return NULL;
+
+    priv = GET_PRIVATE (object);
+
+    device = NM_DEVICE_ETHERNET (nmn_device_handler_get_device (NMN_DEVICE_HANDLER (object)));
+    priv->carrier_changed_id = g_signal_connect (device, "notify::" NM_DEVICE_ETHERNET_CARRIER,
+                                                 G_CALLBACK (carrier_changed), object);
+
+    return object;
+}
+
+static void
+nmn_ethernet_handler_init (NmnEthernetHandler *handler)
+{
+}
+
+static void
+dispose (GObject *object)
+{
+    NmnEthernetHandlerPrivate *priv = GET_PRIVATE (object);
+    NMDevice *device;
+
+    if (priv->disposed)
+        return;
+
+    device = nmn_device_handler_get_device (NMN_DEVICE_HANDLER (object));
+    g_signal_handler_disconnect (device, priv->carrier_changed_id);
+
+    priv->disposed = TRUE;
+
+    G_OBJECT_CLASS (nmn_ethernet_handler_parent_class)->dispose (object);
+}
+
+static void
+nmn_ethernet_handler_class_init (NmnEthernetHandlerClass *class)
+{
+    GObjectClass *object_class = G_OBJECT_CLASS (class);
+    NmnDeviceHandlerClass *handler_class = NMN_DEVICE_HANDLER_CLASS (class);
+
+    g_type_class_add_private (object_class, sizeof (NmnEthernetHandlerPrivate));
+
+    object_class->constructor = constructor;
+    object_class->dispose = dispose;
+
+    handler_class->connection_added = connection_added;
+}
diff --git a/src/nmn-ethernet-handler.h b/src/nmn-ethernet-handler.h
new file mode 100644
index 0000000..29da64b
--- /dev/null
+++ b/src/nmn-ethernet-handler.h
@@ -0,0 +1,30 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+#ifndef NMN_ETHERNET_HANDLER_H
+#define NMN_ETHERNET_HANDLER_H
+
+#include <glib-object.h>
+#include <nm-device-ethernet.h>
+#include "nmn-device-handler.h"
+
+#define NMN_TYPE_ETHERNET_HANDLER            (nmn_ethernet_handler_get_type ())
+#define NMN_ETHERNET_HANDLER(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMN_TYPE_ETHERNET_HANDLER, NmnEthernetHandler))
+#define NMN_ETHERNET_HANDLER_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), NMN_TYPE_ETHERNET_HANDLER, NmnEthernetHandlerClass))
+#define NMN_IS_ETHERNET_HANDLER(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMN_TYPE_ETHERNET_HANDLER))
+#define NMN_IS_ETHERNET_HANDLER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NMN_TYPE_ETHERNET_HANDLER))
+#define NMN_ETHERNET_HANDLER_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NMN_TYPE_ETHERNET_HANDLER, NmnEthernetHandlerClass))
+
+typedef struct {
+    NmnDeviceHandler parent;
+} NmnEthernetHandler;
+
+typedef struct {
+    NmnDeviceHandlerClass parent;
+} NmnEthernetHandlerClass;
+
+GType nmn_ethernet_handler_get_type (void);
+
+NmnDeviceHandler *nmn_ethernet_handler_new (NmnNMData *nm_data,
+                                            NMDeviceEthernet *device);
+
+#endif /* NMN_ETHERNET_HANDLER_H */
diff --git a/src/nmn-ethernet-item.c b/src/nmn-ethernet-item.c
index 947295c..9cac9f7 100644
--- a/src/nmn-ethernet-item.c
+++ b/src/nmn-ethernet-item.c
@@ -1,32 +1,27 @@
 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 
 #include <NetworkManager.h>
-#include <nm-connection.h>
-#include <nm-setting-connection.h>
-#include <nm-setting-wired.h>
 #include "nmn-ethernet-item.h"
-#include "nma-gconf-connection.h"
-#include "utils.h"
 
 G_DEFINE_TYPE (NmnEthernetItem, nmn_ethernet_item, NMN_TYPE_NETWORK_ITEM)
 
 #define GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), NMN_TYPE_ETHERNET_ITEM, NmnEthernetItemPrivate))
 
 typedef struct {
-    GSList *signal_handlers;
-
+    gulong state_changed_id;
     gboolean disposed;
 } NmnEthernetItemPrivate;
 
-
 static void
-update_item (NmnEthernetItem *self)
+state_changed (NMDevice *device,
+               NMDeviceState new_state,
+               NMDeviceState old_state,
+               NMDeviceStateReason reason,
+               gpointer user_data)
 {
     const char *icon;
-    NMDevice *device;
 
-    device = nmn_network_item_get_device (NMN_NETWORK_ITEM (self));
-    switch (nm_device_get_state (device)) {
+    switch (new_state) {
     case NM_DEVICE_STATE_ACTIVATED:
         icon = "nm-device-wired";
         break;
@@ -35,82 +30,50 @@ update_item (NmnEthernetItem *self)
         break;
     }
 
-    nmn_item_set_icon (NMN_ITEM (self), icon);
+    nmn_item_set_icon (NMN_ITEM (user_data), icon);
 }
 
-static void
-state_changed (NMDevice *device,
-               NMDeviceState new_state,
-               NMDeviceState old_state,
-               NMDeviceStateReason reason,
-               gpointer user_data)
+GtkWidget *
+nmn_ethernet_item_new (NmnNMData *nm_data,
+                       NMDeviceEthernet *device)
 {
-    update_item (NMN_ETHERNET_ITEM (user_data));
-}
+    g_return_val_if_fail (NMN_IS_NM_DATA (nm_data), NULL);
+    g_return_val_if_fail (NM_IS_DEVICE_ETHERNET (device), NULL);
 
-static void
-carrier_changed (NMDeviceEthernet *device,
-                 GParamSpec *pspec,
-                 gpointer user_data)
-{
-    if (!nm_device_ethernet_get_carrier (device))
-        nmn_item_remove_request (NMN_ITEM (user_data));
+    return GTK_WIDGET (g_object_new (NMN_TYPE_ETHERNET_ITEM,
+                                     NMN_NETWORK_ITEM_NM_DATA, nm_data,
+                                     NMN_NETWORK_ITEM_DEVICE, device,
+                                     NULL));
 }
 
 static void
-add_signal_handler (gpointer item, gulong id)
+nmn_ethernet_item_init (NmnEthernetItem *item)
 {
-    NmnEthernetItemPrivate *priv = GET_PRIVATE (item);
-    gulong *p;
-
-    p = g_new (gulong, 1);
-    *p = id;
-    priv->signal_handlers = g_slist_prepend (priv->signal_handlers, p);
 }
 
-GtkWidget *
-nmn_ethernet_item_create (NmnNMData *nm_data,
-                          NMDeviceEthernet *device,
-                          NMExportedConnection *exported)
+static GObject*
+constructor (GType type,
+             guint n_construct_params,
+             GObjectConstructParam *construct_params)
 {
-    NMConnection *wrapped;
-    GtkWidget *item;
+    GObject *object;
+    NmnEthernetItemPrivate *priv;
+    NMDevice *device;
 
-    g_return_val_if_fail (NMN_IS_NM_DATA (nm_data), NULL);
-    g_return_val_if_fail (NM_IS_DEVICE_ETHERNET (device), NULL);
-    g_return_val_if_fail (NM_IS_EXPORTED_CONNECTION (exported), NULL);
+    object = G_OBJECT_CLASS (nmn_ethernet_item_parent_class)->constructor
+        (type, n_construct_params, construct_params);
 
-    if (!nm_device_ethernet_get_carrier (device))
-        /* No carrier, no dice */
+    if (!object)
         return NULL;
 
-    wrapped = nm_exported_connection_get_connection (exported);
-    if (utils_connection_valid_for_device (wrapped, NM_DEVICE (device), NULL)) {
-        gulong id;
-
-        item = GTK_WIDGET (g_object_new (NMN_TYPE_ETHERNET_ITEM,
-                                         NMN_NETWORK_ITEM_NM_DATA, nm_data,
-                                         NMN_NETWORK_ITEM_DEVICE, device,
-                                         NMN_NETWORK_ITEM_CONNECTION, exported,
-                                         NULL));
-
-        update_item (NMN_ETHERNET_ITEM (item));
-
-        id = g_signal_connect (device, "state-changed", G_CALLBACK (state_changed), item);
-        add_signal_handler (item, id);
+    priv = GET_PRIVATE (object);
+    device = nmn_network_item_get_device (NMN_NETWORK_ITEM (object));
+    priv->state_changed_id = g_signal_connect (device, "state-changed", G_CALLBACK (state_changed), object);
 
-        id = g_signal_connect (device, "notify::" NM_DEVICE_ETHERNET_CARRIER,
-                               G_CALLBACK (carrier_changed), item);
-        add_signal_handler (item, id);
-    } else
-        item = NULL;
+    state_changed (device, nm_device_get_state (device), 
+                   NM_DEVICE_STATE_UNKNOWN, NM_DEVICE_STATE_REASON_NONE, object);
 
-    return item;
-}
-
-static void
-nmn_ethernet_item_init (NmnEthernetItem *item)
-{
+    return object;
 }
 
 static void
@@ -123,14 +86,7 @@ dispose (GObject *object)
         return;
 
     device = nmn_network_item_get_device (NMN_NETWORK_ITEM (object));
-    while (priv->signal_handlers) {
-        gulong *id = (gulong *) priv->signal_handlers->data;
-
-        g_signal_handler_disconnect (device, *id);
-        g_free (id);
-
-        priv->signal_handlers = g_slist_remove_link (priv->signal_handlers, priv->signal_handlers);
-    }
+    g_signal_handler_disconnect (device, priv->state_changed_id);
 
     priv->disposed = TRUE;
 
@@ -144,5 +100,6 @@ nmn_ethernet_item_class_init (NmnEthernetItemClass *class)
 
     g_type_class_add_private (object_class, sizeof (NmnEthernetItemPrivate));
 
+    object_class->constructor = constructor;
     object_class->dispose = dispose;
 }
diff --git a/src/nmn-ethernet-item.h b/src/nmn-ethernet-item.h
index 26e6d60..75576c9 100644
--- a/src/nmn-ethernet-item.h
+++ b/src/nmn-ethernet-item.h
@@ -24,9 +24,7 @@ typedef struct {
 
 GType nmn_ethernet_item_get_type (void);
 
-GtkWidget *
-nmn_ethernet_item_create (NmnNMData *nm_data,
-                          NMDeviceEthernet *device,
-                          NMExportedConnection *exported);
+GtkWidget *nmn_ethernet_item_new (NmnNMData *nm_data,
+                                  NMDeviceEthernet *device);
 
 #endif /* NMN_ETHERNET_ITEM_H */
diff --git a/src/nmn-networks.c b/src/nmn-networks.c
index 7bf2fe4..1ecdc93 100644
--- a/src/nmn-networks.c
+++ b/src/nmn-networks.c
@@ -10,6 +10,10 @@
 #include "nmn-ethernet-item.h"
 #include "nmn-wifi-item.h"
 #include "nmn-serial-item.h"
+#include "nmn-device-handler.h"
+#include "nmn-ethernet-handler.h"
+#include "nmn-serial-handler.h"
+#include "nmn-wifi-handler.h"
 
 #define DBUS_TYPE_G_ARRAY_OF_OBJECT_PATH (dbus_g_type_get_collection ("GPtrArray", DBUS_TYPE_G_OBJECT_PATH))
 
@@ -26,16 +30,12 @@ enum {
 
 typedef struct {
     NmnNMData *nm_data;
+    GSList *handlers;
     gboolean populated;
 
     gboolean disposed;
 } NmnNetworksPrivate;
 
-static void create_new_item (NmnNetworks *self,
-                             NMDevice *device,
-                             NMExportedConnection *exported);
-
-
 GtkWidget *
 nmn_networks_new (NmnNMData *nm_data)
 {
@@ -79,49 +79,6 @@ find_ac_for_item (NmnNetworks *self, NmnNetworkItem *item)
 }
 
 typedef struct {
-    NmnNetworks *networks;
-    NMDevice *device;
-} DeviceAddedInfo;
-
-static void
-device_added_cb (gpointer data, gpointer user_data)
-{
-    NMExportedConnection *exported = NM_EXPORTED_CONNECTION (data);
-    DeviceAddedInfo *info = (DeviceAddedInfo *) user_data;
-
-    create_new_item (info->networks, info->device, exported);
-}
-
-static void
-device_added (NMClient *client,
-              NMDevice *device,
-              gpointer user_data)
-{
-    NmnNetworks *self = NMN_NETWORKS (user_data);
-    NmnNetworksPrivate *priv = GET_PRIVATE (self);
-    NMSettings *settings;
-    GSList *list;
-    DeviceAddedInfo info;
-
-    info.networks = self;
-    info.device = device;
-
-    settings = nmn_nm_data_get_user_settings (priv->nm_data);
-    if (settings) {
-        list = nm_settings_list_connections (NM_SETTINGS (settings));
-        g_slist_foreach (list, device_added_cb, &info);
-        g_slist_free (list);
-    }
-
-    settings = nmn_nm_data_get_system_settings (priv->nm_data);
-    if (settings) {
-        list = nm_settings_list_connections (NM_SETTINGS (settings));
-        g_slist_foreach (list, device_added_cb, &info);
-        g_slist_free (list);
-    }
-}
-
-typedef struct {
     NmnItem *item;
     NMExportedConnection *exported;
     NMDevice *device;
@@ -166,104 +123,108 @@ remove_connections (NmnNetworks *self,
 }
 
 static void
-device_removed (NMClient *client,
-                NMDevice *device,
-                gpointer user_data)
-{
-    remove_connections (NMN_NETWORKS (user_data), NULL, NULL, device);
-}
-
-static void
-acs_changed_cb (GtkWidget *widget, gpointer data)
-{
-    find_ac_for_item (NMN_NETWORKS (data),
-                      NMN_NETWORK_ITEM (gtk_bin_get_child (GTK_BIN (widget))));
-}
-
-static void
-active_connections_changed (NMClient *client,
-                            GParamSpec *pspec,
-                            gpointer user_data)
+item_remove_requested (NmnItem *item,
+                       gpointer user_data)
 {
-    NmnNetworks *self = NMN_NETWORKS (user_data);
-
-    gtk_container_foreach (GTK_CONTAINER (self), acs_changed_cb, self);
+    remove_connections (NMN_NETWORKS (user_data), item, NULL, NULL);
 }
 
+#if 0
 static void
 connection_removed (NMExportedConnection *connection,
                     gpointer user_data)
 {
     remove_connections (NMN_NETWORKS (user_data), NULL, connection, NULL);
 }
+#endif
 
 static void
-item_remove_requested (NmnItem *item,
-                       gpointer user_data)
+item_added (NmnDeviceHandler *handler,
+            NmnItem *item,
+            gpointer user_data)
 {
-    remove_connections (NMN_NETWORKS (user_data), item, NULL, NULL);
+    NmnNetworks *self = NMN_NETWORKS (user_data);
+    GtkWidget *event_box;
+
+    event_box = gtk_event_box_new ();
+    gtk_container_add (GTK_CONTAINER (event_box), GTK_WIDGET (item));
+    gtk_widget_show_all (event_box);
+    nmn_list_add_item (NMN_LIST (self), event_box);
+    g_signal_connect (item, "remove-requested", G_CALLBACK (item_remove_requested), self);
+
+    find_ac_for_item (self, NMN_NETWORK_ITEM (item));
+    //g_signal_connect (exported, "removed", G_CALLBACK (connection_removed), self);
 }
 
 static void
-create_new_item (NmnNetworks *self,
-                 NMDevice *device,
-                 NMExportedConnection *exported)
+device_added (NMClient *client,
+              NMDevice *device,
+              gpointer user_data)
 {
+    NmnNetworks *self = NMN_NETWORKS (user_data);
     NmnNetworksPrivate *priv = GET_PRIVATE (self);
-    GtkWidget *item;
+    NmnDeviceHandler *handler;
 
     if (NM_IS_DEVICE_WIFI (device))
-        item = nmn_wifi_item_create_for_connection (priv->nm_data, NM_DEVICE_WIFI (device), exported);
+        handler = nmn_wifi_handler_new (priv->nm_data, NM_DEVICE_WIFI (device));
     else if (NM_IS_DEVICE_ETHERNET (device))
-        item = nmn_ethernet_item_create (priv->nm_data, NM_DEVICE_ETHERNET (device), exported);
+        handler = nmn_ethernet_handler_new (priv->nm_data, NM_DEVICE_ETHERNET (device));
     else if (NM_IS_SERIAL_DEVICE (device))
-        item = nmn_serial_item_create (priv->nm_data, NM_SERIAL_DEVICE (device), exported);
+        handler = nmn_serial_handler_new (priv->nm_data, NM_SERIAL_DEVICE (device));
     else {
-        item = NULL;
+        handler = NULL;
         g_warning ("Unhandled device type: '%s'", G_OBJECT_TYPE_NAME (device));
     }
 
-    if (item) {
-        GtkWidget *event_box;
-
-        event_box = gtk_event_box_new ();
-        gtk_container_add (GTK_CONTAINER (event_box), item);
-        gtk_widget_show_all (event_box);
-        nmn_list_add_item (NMN_LIST (self), event_box);
-        g_signal_connect (item, "remove-requested", G_CALLBACK (item_remove_requested), self);
-
-        find_ac_for_item (self, NMN_NETWORK_ITEM (item));
-        g_signal_connect (exported, "removed", G_CALLBACK (connection_removed), self);
+    if (handler) {
+        priv->handlers = g_slist_prepend (priv->handlers, handler);
+        g_signal_connect (handler, "item-added", G_CALLBACK (item_added), self);
+        nmn_device_handler_start (handler);
     }
 }
 
 static void
-connection_added (NMSettings *settings,
-                  NMExportedConnection *exported,
-                  gpointer user_data)
+device_removed (NMClient *client,
+                NMDevice *device,
+                gpointer user_data)
 {
     NmnNetworks *self = NMN_NETWORKS (user_data);
     NmnNetworksPrivate *priv = GET_PRIVATE (self);
-    const GPtrArray *devices;
-    int i;
+    GSList *iter;
 
-    devices = nm_client_get_devices (NM_CLIENT (priv->nm_data));
-    for (i = 0; devices && i < devices->len; i++)
-        create_new_item (self, NM_DEVICE (g_ptr_array_index (devices, i)), exported);
+    for (iter = priv->handlers; iter; iter = iter->next) {
+        if (nmn_device_handler_get_device (NMN_DEVICE_HANDLER (iter->data)) == device) {
+            remove_connections (self, NULL, NULL, device);
+            g_object_unref (iter->data);
+            priv->handlers = g_slist_delete_link (priv->handlers, iter);
+            break;
+        }
+    }
 }
 
 static void
-populate_one_connection (gpointer data, gpointer user_data)
+acs_changed_cb (GtkWidget *widget, gpointer data)
 {
-    connection_added (NULL, NM_EXPORTED_CONNECTION (data), user_data);
+    find_ac_for_item (NMN_NETWORKS (data),
+                      NMN_NETWORK_ITEM (gtk_bin_get_child (GTK_BIN (widget))));
+}
+
+static void
+active_connections_changed (NMClient *client,
+                            GParamSpec *pspec,
+                            gpointer user_data)
+{
+    NmnNetworks *self = NMN_NETWORKS (user_data);
+
+    gtk_container_foreach (GTK_CONTAINER (self), acs_changed_cb, self);
 }
 
 void
 nmn_networks_populate (NmnNetworks *self)
 {
-    NMSettings *settings;
     NmnNetworksPrivate *priv;
-    GSList *list;
+    const GPtrArray *devices;
+    int i;
 
     g_return_if_fail (NMN_IS_NETWORKS (self));
 
@@ -285,23 +246,9 @@ nmn_networks_populate (NmnNetworks *self)
 	                  G_CALLBACK (active_connections_changed),
 	                  self);
 
-    settings = nmn_nm_data_get_user_settings (priv->nm_data);
-    if (settings) {
-        g_signal_connect (settings, "new-connection", G_CALLBACK (connection_added), self);
-
-        list = nm_settings_list_connections (settings);
-        g_slist_foreach (list, populate_one_connection, self);
-        g_slist_free (list);
-    }
-
-    settings = nmn_nm_data_get_system_settings (priv->nm_data);
-    if (settings) {
-        g_signal_connect (settings, "new-connection", G_CALLBACK (connection_added), self);
-
-        list = nm_settings_list_connections (settings);
-        g_slist_foreach (list, populate_one_connection, self);
-        g_slist_free (list);
-    }
+    devices = nm_client_get_devices (NM_CLIENT (priv->nm_data));
+    for (i = 0; devices && i < devices->len; i++)
+        device_added (NM_CLIENT (priv->nm_data), NM_DEVICE (g_ptr_array_index (devices, i)), self);
 }
 
 static void
@@ -375,6 +322,9 @@ dispose (GObject *object)
     if (priv->disposed)
         return;
 
+    g_slist_foreach (priv->handlers, (GFunc) g_object_unref, NULL);
+    g_slist_free (priv->handlers);
+
     g_object_unref (priv->nm_data);
 
     priv->disposed = TRUE;
diff --git a/src/nmn-serial-handler.c b/src/nmn-serial-handler.c
new file mode 100644
index 0000000..0219172
--- /dev/null
+++ b/src/nmn-serial-handler.c
@@ -0,0 +1,53 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+#include <nm-settings.h>
+#include "nmn-serial-handler.h"
+#include "nmn-serial-item.h"
+#include "utils.h"
+
+G_DEFINE_TYPE (NmnSerialHandler, nmn_serial_handler, NMN_TYPE_DEVICE_HANDLER)
+
+NmnDeviceHandler *
+nmn_serial_handler_new (NmnNMData *nm_data,
+                        NMSerialDevice *device)
+{
+    g_return_val_if_fail (NMN_IS_NM_DATA (nm_data), NULL);
+    g_return_val_if_fail (NM_IS_SERIAL_DEVICE (device), NULL);
+
+    return NMN_DEVICE_HANDLER (g_object_new (NMN_TYPE_SERIAL_HANDLER,
+                                             NMN_DEVICE_HANDLER_NM_DATA, nm_data,
+                                             NMN_DEVICE_HANDLER_DEVICE, device,
+                                             NULL));
+}
+
+static void
+connection_added (NmnDeviceHandler *handler,
+                  NMExportedConnection *exported)
+{
+    NMConnection *wrapped;
+    NMDevice *device;
+    GtkWidget *item;
+
+    wrapped = nm_exported_connection_get_connection (exported);
+    device = nmn_device_handler_get_device (handler);
+
+    if (!utils_connection_valid_for_device (wrapped, device, NULL))
+        return;
+
+    item = nmn_serial_item_new (nmn_device_handler_get_nm_data (handler), NM_SERIAL_DEVICE (device));
+    g_object_set (item, NMN_NETWORK_ITEM_CONNECTION, exported, NULL);
+    nmn_device_handler_add_item (handler, NMN_ITEM (item));
+}
+
+static void
+nmn_serial_handler_init (NmnSerialHandler *handler)
+{
+}
+
+static void
+nmn_serial_handler_class_init (NmnSerialHandlerClass *class)
+{
+    NmnDeviceHandlerClass *handler_class = NMN_DEVICE_HANDLER_CLASS (class);
+
+    handler_class->connection_added = connection_added;
+}
diff --git a/src/nmn-serial-handler.h b/src/nmn-serial-handler.h
new file mode 100644
index 0000000..9b20512
--- /dev/null
+++ b/src/nmn-serial-handler.h
@@ -0,0 +1,30 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+#ifndef NMN_SERIAL_HANDLER_H
+#define NMN_SERIAL_HANDLER_H
+
+#include <glib-object.h>
+#include <nm-serial-device.h>
+#include "nmn-device-handler.h"
+
+#define NMN_TYPE_SERIAL_HANDLER            (nmn_serial_handler_get_type ())
+#define NMN_SERIAL_HANDLER(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMN_TYPE_SERIAL_HANDLER, NmnSerialHandler))
+#define NMN_SERIAL_HANDLER_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), NMN_TYPE_SERIAL_HANDLER, NmnSerialHandlerClass))
+#define NMN_IS_SERIAL_HANDLER(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMN_TYPE_SERIAL_HANDLER))
+#define NMN_IS_SERIAL_HANDLER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NMN_TYPE_SERIAL_HANDLER))
+#define NMN_SERIAL_HANDLER_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NMN_TYPE_SERIAL_HANDLER, NmnSerialHandlerClass))
+
+typedef struct {
+    NmnDeviceHandler parent;
+} NmnSerialHandler;
+
+typedef struct {
+    NmnDeviceHandlerClass parent;
+} NmnSerialHandlerClass;
+
+GType nmn_serial_handler_get_type (void);
+
+NmnDeviceHandler *nmn_serial_handler_new (NmnNMData *nm_data,
+                                          NMSerialDevice *device);
+
+#endif /* NMN_SERIAL_HANDLER_H */
diff --git a/src/nmn-serial-item.c b/src/nmn-serial-item.c
index cb9a47b..680b0b7 100644
--- a/src/nmn-serial-item.c
+++ b/src/nmn-serial-item.c
@@ -13,19 +13,21 @@ G_DEFINE_TYPE (NmnSerialItem, nmn_serial_item, NMN_TYPE_NETWORK_ITEM)
 #define GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), NMN_TYPE_SERIAL_ITEM, NmnSerialItemPrivate))
 
 typedef struct {
-    GSList *signal_handlers;
+    gulong state_changed_id;
 
     gboolean disposed;
 } NmnSerialItemPrivate;
 
 static void
-update_item (NmnSerialItem *self)
+state_changed (NMDevice *device,
+               NMDeviceState new_state,
+               NMDeviceState old_state,
+               NMDeviceStateReason reason,
+               gpointer user_data)
 {
     const char *icon;
-    NMDevice *device;
 
-    device = nmn_network_item_get_device (NMN_NETWORK_ITEM (self));
-    switch (nm_device_get_state (device)) {
+    switch (new_state) {
     case NM_DEVICE_STATE_ACTIVATED:
         icon = "nm-device-wwan";
         break;
@@ -34,66 +36,51 @@ update_item (NmnSerialItem *self)
         break;
     }
 
-    nmn_item_set_icon (NMN_ITEM (self), icon);
+    nmn_item_set_icon (NMN_ITEM (user_data), icon);
 }
 
-static void
-state_changed (NMDevice *device,
-               NMDeviceState new_state,
-               NMDeviceState old_state,
-               NMDeviceStateReason reason,
-               gpointer user_data)
+GtkWidget *
+nmn_serial_item_new (NmnNMData *nm_data,
+                     NMSerialDevice *device)
 {
-    update_item (NMN_SERIAL_ITEM (user_data));
+    g_return_val_if_fail (NMN_IS_NM_DATA (nm_data), NULL);
+    g_return_val_if_fail (NM_IS_SERIAL_DEVICE (device), NULL);
+
+    return GTK_WIDGET (g_object_new (NMN_TYPE_SERIAL_ITEM,
+                                     NMN_NETWORK_ITEM_NM_DATA, nm_data,
+                                     NMN_NETWORK_ITEM_DEVICE, device,
+                                     NULL));
 }
 
 static void
-add_signal_handler (gpointer item, gulong id)
+nmn_serial_item_init (NmnSerialItem *item)
 {
-    NmnSerialItemPrivate *priv = GET_PRIVATE (item);
-    gulong *p;
-
-    p = g_new (gulong, 1);
-    *p = id;
-    priv->signal_handlers = g_slist_prepend (priv->signal_handlers, p);
+    nmn_item_set_remove_visible (NMN_ITEM (item), TRUE);
 }
 
-GtkWidget *
-nmn_serial_item_create (NmnNMData *nm_data,
-                        NMSerialDevice *device,
-                        NMExportedConnection *exported)
+static GObject*
+constructor (GType type,
+             guint n_construct_params,
+             GObjectConstructParam *construct_params)
 {
-    NMConnection *wrapped;
-    GtkWidget *item;
-
-    g_return_val_if_fail (NMN_IS_NM_DATA (nm_data), NULL);
-    g_return_val_if_fail (NM_IS_SERIAL_DEVICE (device), NULL);
-    g_return_val_if_fail (NM_IS_EXPORTED_CONNECTION (exported), NULL);
-
-    wrapped = nm_exported_connection_get_connection (exported);
-    if (utils_connection_valid_for_device (wrapped, NM_DEVICE (device), NULL)) {
-        gulong id;
+    GObject *object;
+    NmnSerialItemPrivate *priv;
+    NMDevice *device;
 
-        item = GTK_WIDGET (g_object_new (NMN_TYPE_SERIAL_ITEM,
-                                         NMN_NETWORK_ITEM_NM_DATA, nm_data,
-                                         NMN_NETWORK_ITEM_DEVICE, device,
-                                         NMN_NETWORK_ITEM_CONNECTION, exported,
-                                         NULL));
+    object = G_OBJECT_CLASS (nmn_serial_item_parent_class)->constructor
+        (type, n_construct_params, construct_params);
 
-        update_item (NMN_SERIAL_ITEM (item));
-        nmn_item_set_remove_visible (NMN_ITEM (item), TRUE);
+    if (!object)
+        return NULL;
 
-        id = g_signal_connect (device, "state-changed", G_CALLBACK (state_changed), item);
-        add_signal_handler (item, id);
-    } else
-        item = NULL;
+    priv = GET_PRIVATE (object);
+    device = nmn_network_item_get_device (NMN_NETWORK_ITEM (object));
+    priv->state_changed_id = g_signal_connect (device, "state-changed", G_CALLBACK (state_changed), object);
 
-    return item;
-}
+    state_changed (device, nm_device_get_state (device), 
+                   NM_DEVICE_STATE_UNKNOWN, NM_DEVICE_STATE_REASON_NONE, object);
 
-static void
-nmn_serial_item_init (NmnSerialItem *item)
-{
+    return object;
 }
 
 static void
@@ -106,14 +93,7 @@ dispose (GObject *object)
         return;
 
     device = nmn_network_item_get_device (NMN_NETWORK_ITEM (object));
-    while (priv->signal_handlers) {
-        gulong *id = (gulong *) priv->signal_handlers->data;
-
-        g_signal_handler_disconnect (device, *id);
-        g_free (id);
-
-        priv->signal_handlers = g_slist_remove_link (priv->signal_handlers, priv->signal_handlers);
-    }
+    g_signal_handler_disconnect (device, priv->state_changed_id);
 
     priv->disposed = TRUE;
 
@@ -127,5 +107,6 @@ nmn_serial_item_class_init (NmnSerialItemClass *class)
 
     g_type_class_add_private (object_class, sizeof (NmnSerialItemPrivate));
 
+    object_class->constructor = constructor;
     object_class->dispose = dispose;
 }
diff --git a/src/nmn-serial-item.h b/src/nmn-serial-item.h
index 1571f54..286acd9 100644
--- a/src/nmn-serial-item.h
+++ b/src/nmn-serial-item.h
@@ -24,9 +24,7 @@ typedef struct {
 
 GType nmn_serial_item_get_type (void);
 
-GtkWidget *
-nmn_serial_item_create (NmnNMData *nm_data,
-                        NMSerialDevice *device,
-                        NMExportedConnection *exported);
+GtkWidget *nmn_serial_item_new (NmnNMData *nm_data,
+                                NMSerialDevice *device);
 
 #endif /* NMN_SERIAL_ITEM_H */
diff --git a/src/nmn-wifi-handler.c b/src/nmn-wifi-handler.c
new file mode 100644
index 0000000..2c7a5b9
--- /dev/null
+++ b/src/nmn-wifi-handler.c
@@ -0,0 +1,253 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+#include <string.h>
+#include <nm-settings.h>
+#include <nm-setting-connection.h>
+#include <nm-setting-wireless.h>
+#include "nmn-wifi-handler.h"
+#include "nmn-wifi-item.h"
+#include "utils.h"
+
+G_DEFINE_TYPE (NmnWifiHandler, nmn_wifi_handler, NMN_TYPE_DEVICE_HANDLER)
+
+#define GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), NMN_TYPE_WIFI_HANDLER, NmnWifiHandlerPrivate))
+
+typedef struct {
+    gulong ap_added_id;
+    gulong ap_removed_id;
+    gulong ap_changed_id;
+
+    gboolean disposed;
+} NmnWifiHandlerPrivate;
+
+NmnDeviceHandler *
+nmn_wifi_handler_new (NmnNMData *nm_data,
+                      NMDeviceWifi *device)
+{
+    g_return_val_if_fail (NMN_IS_NM_DATA (nm_data), NULL);
+    g_return_val_if_fail (NM_IS_DEVICE_WIFI (device), NULL);
+
+    return NMN_DEVICE_HANDLER (g_object_new (NMN_TYPE_WIFI_HANDLER,
+                                             NMN_DEVICE_HANDLER_NM_DATA, nm_data,
+                                             NMN_DEVICE_HANDLER_DEVICE, device,
+                                             NULL));
+}
+
+static NMAccessPoint *
+find_best_ap_for_connection (NMDeviceWifi *device,
+                             NMExportedConnection *connection)
+{
+    const GPtrArray *aps;
+    NMConnection *wrapped;
+    NMAccessPoint *best_ap = NULL;
+    int i;
+
+    wrapped = nm_exported_connection_get_connection (connection);
+    aps = nm_device_wifi_get_access_points (device);
+    for (i = 0; aps && i < aps->len; i++) {
+        NMAccessPoint *ap = NM_ACCESS_POINT (g_ptr_array_index (aps, i));
+
+        if (utils_connection_valid_for_device (wrapped, NM_DEVICE (device), ap)) {
+            if (!best_ap)
+                best_ap = ap;
+            else if (nm_access_point_get_strength (best_ap) < nm_access_point_get_strength (ap))
+                best_ap = ap;
+        }
+    }
+
+    return best_ap;
+}
+
+static void
+update_items (NmnWifiHandler *self)
+{
+    GSList *list;
+    GSList *iter;
+    NMDeviceWifi *device;
+
+    device = NM_DEVICE_WIFI (nmn_device_handler_get_device (NMN_DEVICE_HANDLER (self)));
+    list = nmn_device_handler_get_items (NMN_DEVICE_HANDLER (self));
+
+    for (iter = list; iter; iter = iter->next) {
+        NmnWifiItem *item = NMN_WIFI_ITEM (iter->data);
+        NMAccessPoint *current_ap = nmn_wifi_item_get_ap (item);
+        NMAccessPoint *best_ap;
+
+        best_ap = nm_device_wifi_get_active_access_point (device);
+        if (!best_ap) {
+            NMExportedConnection *exported;
+
+            exported = nmn_network_item_get_connection (NMN_NETWORK_ITEM (item));
+            best_ap = find_best_ap_for_connection (device, exported);
+        }
+
+        if (!best_ap)
+            nmn_item_remove_request (NMN_ITEM (item));
+        else if (best_ap != current_ap)
+            nmn_wifi_item_set_ap (item, best_ap);
+    }
+}
+
+static void
+ap_updated (NMAccessPoint *ap,
+            GParamSpec *pspec,
+            gpointer user_data)
+{
+    update_items (NMN_WIFI_HANDLER (user_data));
+}
+
+static void
+ap_removed (NMDeviceWifi *device,
+            NMAccessPoint *ap,
+            gpointer user_data)
+{
+    g_signal_handlers_disconnect_by_func (ap, "notify", ap_updated);
+    update_items (NMN_WIFI_HANDLER (user_data));
+}
+
+static void
+connection_added (NmnDeviceHandler *handler,
+                  NMExportedConnection *exported)
+{
+    NMConnection *wrapped;
+    NMSettingConnection *s_con;
+    const char *connection_type;
+    NMDeviceWifi *device;
+    NMAccessPoint *ap;
+    GtkWidget *item;
+
+    wrapped = nm_exported_connection_get_connection (exported);
+    s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (wrapped, NM_TYPE_SETTING_CONNECTION));
+    connection_type = nm_setting_connection_get_connection_type (s_con);
+
+    if (!connection_type && strcmp (connection_type, NM_SETTING_WIRELESS_SETTING_NAME))
+        /* Not a wifi connection */
+        return;
+
+    /* Make sure it doesn't exist yet */
+    if (nmn_device_handler_get_item_for_connection (handler, exported))
+        return;
+
+    device = NM_DEVICE_WIFI (nmn_device_handler_get_device (handler));
+    ap = find_best_ap_for_connection (device, exported);
+    if (ap) {
+        item = nmn_wifi_item_new (nmn_device_handler_get_nm_data (handler), device, ap);
+        g_object_set (item, NMN_NETWORK_ITEM_CONNECTION, exported, NULL);
+        nmn_item_set_remove_visible (NMN_ITEM (item), TRUE);
+        nmn_device_handler_add_item (handler, NMN_ITEM (item));
+    }
+}
+
+static void
+ap_added (NMDeviceWifi *device,
+          NMAccessPoint *ap,
+          gpointer user_data)
+{
+    NmnDeviceHandler *handler = NMN_DEVICE_HANDLER (user_data);
+    GSList *list;
+    GSList *iter;
+
+    /* Catch the signals of the new AP */
+    g_signal_connect (ap, "notify", G_CALLBACK (ap_updated), handler);
+
+    /* */
+    update_items (NMN_WIFI_HANDLER (handler));
+
+    /* Maybe there's an existing connection for it which hasn't been added yet? */
+    list = nmn_device_handler_get_connections (handler);
+    for (iter = list; iter; iter = iter->next)
+        connection_added (handler, NM_EXPORTED_CONNECTION (iter->data));
+
+    g_slist_free (list);
+}
+
+static void
+active_ap_changed (NMDeviceWifi *device,
+                   GParamSpec *pspec,
+                   gpointer user_data)
+{
+    update_items (NMN_WIFI_HANDLER (user_data));
+}
+
+static GObject*
+constructor (GType type,
+             guint n_construct_params,
+             GObjectConstructParam *construct_params)
+{
+    GObject *object;
+    NmnWifiHandlerPrivate *priv;
+    NMDeviceWifi *device;
+    const GPtrArray *aps;
+    int i;
+
+    object = G_OBJECT_CLASS (nmn_wifi_handler_parent_class)->constructor
+        (type, n_construct_params, construct_params);
+
+    if (!object)
+        return NULL;
+
+    priv = GET_PRIVATE (object);
+    device = NM_DEVICE_WIFI (nmn_device_handler_get_device (NMN_DEVICE_HANDLER (object)));
+
+    priv->ap_added_id   = g_signal_connect (device, "access-point-added", G_CALLBACK (ap_added), object);
+    priv->ap_removed_id = g_signal_connect (device, "access-point-removed", G_CALLBACK (ap_removed), object);
+    priv->ap_changed_id = g_signal_connect (device, "notify::" NM_DEVICE_WIFI_ACTIVE_ACCESS_POINT,
+                                            G_CALLBACK (active_ap_changed), object);
+
+    aps = nm_device_wifi_get_access_points (device);
+    for (i = 0; aps && i < aps->len; i++) {
+        NMAccessPoint *ap = NM_ACCESS_POINT (g_ptr_array_index (aps, i));
+
+        g_signal_connect (ap, "notify", G_CALLBACK (ap_updated), object);
+    }
+
+    return object;
+}
+
+static void
+nmn_wifi_handler_init (NmnWifiHandler *handler)
+{
+}
+
+static void
+dispose (GObject *object)
+{
+    NmnWifiHandlerPrivate *priv = GET_PRIVATE (object);
+    NMDeviceWifi *device;
+    const GPtrArray *aps;
+    int i;
+
+    if (priv->disposed)
+        return;
+
+    device = NM_DEVICE_WIFI (nmn_device_handler_get_device (NMN_DEVICE_HANDLER (object)));
+
+    aps = nm_device_wifi_get_access_points (device);
+    for (i = 0; aps && i < aps->len; i++) {
+        NMAccessPoint *ap = NM_ACCESS_POINT (g_ptr_array_index (aps, i));
+
+        g_signal_handlers_disconnect_by_func (ap, "notify", ap_updated);
+    }
+
+    g_signal_handler_disconnect (device, priv->ap_added_id);
+    g_signal_handler_disconnect (device, priv->ap_removed_id);
+    g_signal_handler_disconnect (device, priv->ap_changed_id);
+
+    priv->disposed = TRUE;
+
+    G_OBJECT_CLASS (nmn_wifi_handler_parent_class)->dispose (object);
+}
+
+static void
+nmn_wifi_handler_class_init (NmnWifiHandlerClass *class)
+{
+    GObjectClass *object_class = G_OBJECT_CLASS (class);
+    NmnDeviceHandlerClass *handler_class = NMN_DEVICE_HANDLER_CLASS (class);
+
+    g_type_class_add_private (object_class, sizeof (NmnWifiHandlerPrivate));
+
+    object_class->constructor = constructor;
+    object_class->dispose = dispose;
+
+    handler_class->connection_added = connection_added;
+}
diff --git a/src/nmn-wifi-handler.h b/src/nmn-wifi-handler.h
new file mode 100644
index 0000000..88a9014
--- /dev/null
+++ b/src/nmn-wifi-handler.h
@@ -0,0 +1,30 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+#ifndef NMN_WIFI_HANDLER_H
+#define NMN_WIFI_HANDLER_H
+
+#include <glib-object.h>
+#include <nm-device-wifi.h>
+#include "nmn-device-handler.h"
+
+#define NMN_TYPE_WIFI_HANDLER            (nmn_wifi_handler_get_type ())
+#define NMN_WIFI_HANDLER(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMN_TYPE_WIFI_HANDLER, NmnWifiHandler))
+#define NMN_WIFI_HANDLER_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), NMN_TYPE_WIFI_HANDLER, NmnWifiHandlerClass))
+#define NMN_IS_WIFI_HANDLER(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMN_TYPE_WIFI_HANDLER))
+#define NMN_IS_WIFI_HANDLER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NMN_TYPE_WIFI_HANDLER))
+#define NMN_WIFI_HANDLER_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NMN_TYPE_WIFI_HANDLER, NmnWifiHandlerClass))
+
+typedef struct {
+    NmnDeviceHandler parent;
+} NmnWifiHandler;
+
+typedef struct {
+    NmnDeviceHandlerClass parent;
+} NmnWifiHandlerClass;
+
+GType nmn_wifi_handler_get_type (void);
+
+NmnDeviceHandler *nmn_wifi_handler_new (NmnNMData *nm_data,
+                                        NMDeviceWifi *device);
+
+#endif /* NMN_WIFI_HANDLER_H */
diff --git a/src/nmn-wifi-item.c b/src/nmn-wifi-item.c
index 4be3990..027295e 100644
--- a/src/nmn-wifi-item.c
+++ b/src/nmn-wifi-item.c
@@ -151,6 +151,30 @@ nmn_wifi_item_create_for_connection (NmnNMData *nm_data,
     return item;
 }
 
+void
+nmn_wifi_item_set_ap (NmnWifiItem *self,
+                      NMAccessPoint *ap)
+{
+    NmnWifiItemPrivate *priv;
+
+    g_return_if_fail (NMN_IS_WIFI_ITEM (self));
+
+    priv = GET_PRIVATE (self);
+
+    if (priv->ap) {
+        g_signal_handler_disconnect (priv->ap, priv->notify_id);
+        g_object_unref (priv->ap);
+    }
+
+    if (ap) {
+        priv->ap = g_object_ref (ap);
+        priv->notify_id = g_signal_connect (ap, "notify", G_CALLBACK (updated), self);
+    } else
+        priv->ap = NULL;
+
+    update_item (self);
+}
+
 NMAccessPoint *
 nmn_wifi_item_get_ap (NmnWifiItem *self)
 {
@@ -635,9 +659,6 @@ constructor (GType type,
         return NULL;
     }
 
-    priv->notify_id = g_signal_connect (priv->ap, "notify", G_CALLBACK (updated), object);
-    update_item (NMN_WIFI_ITEM (object));
-
     return object;
 }
 
@@ -645,12 +666,11 @@ static void
 set_property (GObject *object, guint prop_id,
               const GValue *value, GParamSpec *pspec)
 {
-    NmnWifiItemPrivate *priv = GET_PRIVATE (object);
+    NmnWifiItem *self = NMN_WIFI_ITEM (object);
 
     switch (prop_id) {
     case PROP_ACCESS_POINT:
-        /* Construct only */
-        priv->ap = g_value_dup_object (value);
+        nmn_wifi_item_set_ap (self, (NMAccessPoint *) g_value_get_object (value));
         break;
     default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -662,11 +682,11 @@ static void
 get_property (GObject *object, guint prop_id,
               GValue *value, GParamSpec *pspec)
 {
-    NmnWifiItemPrivate *priv = GET_PRIVATE (object);
+    NmnWifiItem *self = NMN_WIFI_ITEM (object);
 
     switch (prop_id) {
     case PROP_ACCESS_POINT:
-        g_value_set_object (value, priv->ap);
+        g_value_set_object (value, nmn_wifi_item_get_ap (self));
         break;
     default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -682,10 +702,7 @@ dispose (GObject *object)
     if (priv->disposed)
         return;
 
-    if (priv->ap) {
-        g_signal_handler_disconnect (priv->ap, priv->notify_id);
-        g_object_unref (priv->ap);
-    }
+    nmn_wifi_item_set_ap (NMN_WIFI_ITEM (object), NULL);
 
     priv->disposed = TRUE;
 
diff --git a/src/nmn-wifi-item.h b/src/nmn-wifi-item.h
index 4ddd223..d211c36 100644
--- a/src/nmn-wifi-item.h
+++ b/src/nmn-wifi-item.h
@@ -34,6 +34,9 @@ GtkWidget     *nmn_wifi_item_create_for_connection (NmnNMData *nm_data,
                                                     NMDeviceWifi *device,
                                                     NMExportedConnection *exported);
 
+void           nmn_wifi_item_set_ap                (NmnWifiItem *self,
+                                                    NMAccessPoint *ap);
+
 NMAccessPoint *nmn_wifi_item_get_ap                (NmnWifiItem *self);
 
 #endif /* NMN_WIFI_ITEM_H */



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