[network-manager-netbook/MplPanelClient] The great rewrite.



commit f8df6c92a2e17931d3d6b9bfe5713231e292c94b
Author: Tambet Ingo <tambet gmail com>
Date:   Fri Nov 27 16:02:04 2009 +0200

    The great rewrite.
    
    Rewrite most of the code to:
    * Use model-view design for lists, it was getting out of hand.
    * Split out libnm-gtk which could be shared with nm-applet.
    * Show all available APs in the main list (with different background).

 .gitignore                                         |    6 -
 Makefile.am                                        |    2 +-
 configure.in                                       |    8 +-
 libnm-gtk/.gitignore                               |    1 +
 libnm-gtk/Makefile.am                              |   95 ++
 {src/gconf-helpers => libnm-gtk}/gconf-helpers.c   |   43 +-
 {src/gconf-helpers => libnm-gtk}/gconf-helpers.h   |    2 +-
 {src/gconf-helpers => libnm-gtk}/gconf-upgrade.c   |    0
 {src/gconf-helpers => libnm-gtk}/gconf-upgrade.h   |    0
 libnm-gtk/nm-cdma-item.c                           |   76 ++
 libnm-gtk/nm-cdma-item.h                           |   52 +
 libnm-gtk/nm-cdma-provider.c                       |   71 ++
 libnm-gtk/nm-cdma-provider.h                       |   51 +
 libnm-gtk/nm-connection-item.c                     |  371 +++++++
 libnm-gtk/nm-connection-item.h                     |   61 ++
 libnm-gtk/nm-connection-list.c                     |  276 ++++++
 libnm-gtk/nm-connection-list.h                     |   54 +
 libnm-gtk/nm-connection-model.c                    |  203 ++++
 libnm-gtk/nm-connection-model.h                    |   60 ++
 libnm-gtk/nm-device-handler.c                      |  263 +++++
 libnm-gtk/nm-device-handler.h                      |   60 ++
 libnm-gtk/nm-device-item.c                         |  176 ++++
 libnm-gtk/nm-device-item.h                         |   55 ++
 libnm-gtk/nm-device-model.c                        |  266 +++++
 libnm-gtk/nm-device-model.h                        |   61 ++
 libnm-gtk/nm-device-provider.c                     |  154 +++
 libnm-gtk/nm-device-provider.h                     |   59 ++
 libnm-gtk/nm-ethernet-item.c                       |  116 +++
 libnm-gtk/nm-ethernet-item.h                       |   52 +
 libnm-gtk/nm-ethernet-provider.c                   |   71 ++
 libnm-gtk/nm-ethernet-provider.h                   |   51 +
 .../nm-gconf-connection.c                          |  150 ++--
 libnm-gtk/nm-gconf-connection.h                    |   78 ++
 .../nm-gconf-settings.c                            |  154 ++--
 .../nm-gconf-settings.h                            |   38 +-
 libnm-gtk/nm-gsm-item.c                            |   76 ++
 libnm-gtk/nm-gsm-item.h                            |   52 +
 libnm-gtk/nm-gsm-provider.c                        |   71 ++
 libnm-gtk/nm-gsm-provider.h                        |   51 +
 src/nmn-icon-cache.c => libnm-gtk/nm-icon-cache.c  |   37 +-
 src/nmn-icon-cache.h => libnm-gtk/nm-icon-cache.h  |   10 +-
 libnm-gtk/nm-item-provider.c                       |  308 ++++++
 libnm-gtk/nm-item-provider.h                       |   79 ++
 libnm-gtk/nm-list-item.c                           |  343 +++++++
 libnm-gtk/nm-list-item.h                           |   93 ++
 libnm-gtk/nm-list-model.c                          |  314 ++++++
 libnm-gtk/nm-list-model.h                          |   67 ++
 libnm-gtk/nm-status-icon.c                         |  244 +++++
 libnm-gtk/nm-status-icon.h                         |   51 +
 libnm-gtk/nm-status-model.c                        |  126 +++
 libnm-gtk/nm-status-model.h                        |   55 ++
 libnm-gtk/nm-wifi-item.c                           |  592 +++++++++++
 libnm-gtk/nm-wifi-item.h                           |   63 ++
 libnm-gtk/nm-wifi-provider.c                       |  229 +++++
 libnm-gtk/nm-wifi-provider.h                       |   51 +
 libnm-gtk/test.c                                   |  224 +++++
 libnm-gtk/utils.c                                  |  856 ++++++++++++++++
 libnm-gtk/utils.h                                  |   57 ++
 {src => libnm-gtk}/wireless-dialog.c               |    2 -
 {src => libnm-gtk}/wireless-dialog.h               |    0
 {src => libnm-gtk}/wireless-helper.h               |    0
 {src => libnm-gtk}/wireless-security.ui            |    0
 {src => libnm-gtk}/wireless-security/Makefile.am   |    5 +-
 .../wireless-security/ca-nag-dialog.ui             |    0
 .../wireless-security/dynamic-wep.ui               |    0
 {src => libnm-gtk}/wireless-security/eap-leap.ui   |    0
 .../wireless-security/eap-method-leap.c            |    0
 .../wireless-security/eap-method-leap.h            |    0
 .../wireless-security/eap-method-peap.c            |    0
 .../wireless-security/eap-method-peap.h            |    0
 .../wireless-security/eap-method-simple.c          |    0
 .../wireless-security/eap-method-simple.h          |    0
 .../wireless-security/eap-method-tls.c             |    0
 .../wireless-security/eap-method-tls.h             |    0
 .../wireless-security/eap-method-ttls.c            |    0
 .../wireless-security/eap-method-ttls.h            |    0
 {src => libnm-gtk}/wireless-security/eap-method.c  |    0
 {src => libnm-gtk}/wireless-security/eap-method.h  |    0
 {src => libnm-gtk}/wireless-security/eap-peap.ui   |    0
 {src => libnm-gtk}/wireless-security/eap-simple.ui |    0
 {src => libnm-gtk}/wireless-security/eap-tls.ui    |    0
 {src => libnm-gtk}/wireless-security/eap-ttls.ui   |    0
 {src => libnm-gtk}/wireless-security/helpers.c     |    0
 {src => libnm-gtk}/wireless-security/helpers.h     |    0
 {src => libnm-gtk}/wireless-security/leap.ui       |    0
 {src => libnm-gtk}/wireless-security/wep-key.ui    |    0
 .../wireless-security/wireless-security.c          |    0
 .../wireless-security/wireless-security.h          |    0
 {src => libnm-gtk}/wireless-security/wpa-eap.ui    |    0
 {src => libnm-gtk}/wireless-security/wpa-psk.ui    |    0
 .../wireless-security/ws-dynamic-wep.c             |    0
 .../wireless-security/ws-dynamic-wep.h             |    0
 {src => libnm-gtk}/wireless-security/ws-leap.c     |    1 -
 {src => libnm-gtk}/wireless-security/ws-leap.h     |    0
 {src => libnm-gtk}/wireless-security/ws-wep-key.c  |    2 -
 {src => libnm-gtk}/wireless-security/ws-wep-key.h  |    0
 {src => libnm-gtk}/wireless-security/ws-wpa-eap.c  |    0
 {src => libnm-gtk}/wireless-security/ws-wpa-eap.h  |    0
 {src => libnm-gtk}/wireless-security/ws-wpa-psk.c  |    1 -
 {src => libnm-gtk}/wireless-security/ws-wpa-psk.h  |    0
 marshallers/.gitignore                             |    2 +
 {src/marshallers => marshallers}/Makefile.am       |    0
 .../marshallers => marshallers}/nma-marshal-main.c |    0
 {src/marshallers => marshallers}/nma-marshal.list  |    0
 po/.gitignore                                      |    2 +
 po/POTFILES.in                                     |   53 +-
 src/.gitignore                                     |    1 +
 src/Makefile.am                                    |   60 +-
 src/gconf-helpers/Makefile.am                      |   21 -
 src/gconf-helpers/nma-gconf-connection.h           |   78 --
 src/main.c                                         |   79 +-
 src/nmn-applet.c                                   |  294 ++-----
 src/nmn-applet.h                                   |   19 +-
 src/nmn-device-handler.c                           |  379 --------
 src/nmn-device-handler.h                           |   73 --
 src/nmn-ethernet-handler.c                         |  188 ----
 src/nmn-ethernet-handler.h                         |   47 -
 src/nmn-ethernet-item.c                            |  133 ---
 src/nmn-ethernet-item.h                            |   47 -
 src/nmn-item-renderer.c                            |  445 +++++++++
 src/nmn-item-renderer.h                            |   51 +
 src/nmn-item.c                                     |  151 ---
 src/nmn-item.h                                     |   62 --
 src/nmn-list.c                                     |  552 ++++++-----
 src/nmn-list.h                                     |   10 +-
 src/nmn-model.c                                    |  433 +++++++++
 src/nmn-model.h                                    |   80 ++
 src/nmn-network-item.c                             | 1025 --------------------
 src/nmn-network-item.h                             |  105 --
 src/nmn-networks.c                                 |  471 ---------
 src/nmn-networks.h                                 |   48 -
 src/nmn-new-connection.c                           |  111 ++-
 src/nmn-new-connection.h                           |    6 +-
 src/nmn-nm-data.c                                  |  327 -------
 src/nmn-nm-data.h                                  |   79 --
 src/nmn-panel-client.c                             |  388 ++++++++
 src/nmn-panel-client.h                             |   52 +
 src/nmn-serial-handler.c                           |  134 ---
 src/nmn-serial-handler.h                           |   47 -
 src/nmn-serial-item.c                              |  157 ---
 src/nmn-serial-item.h                              |   47 -
 src/nmn-status-icon.c                              |  632 ------------
 src/nmn-status-icon.h                              |   55 --
 src/nmn-text-item.c                                |  102 --
 src/nmn-text-item.h                                |   44 -
 src/nmn-wifi-handler.c                             |  375 -------
 src/nmn-wifi-handler.h                             |   47 -
 src/nmn-wifi-item.c                                |  743 --------------
 src/nmn-wifi-item.h                                |   60 --
 src/nmn-wifi-list.c                                |  428 --------
 src/nmn-wifi-list.h                                |   50 -
 src/utils.c                                        |  825 ----------------
 src/utils.h                                        |   56 +-
 153 files changed, 9115 insertions(+), 7855 deletions(-)
---
diff --git a/.gitignore b/.gitignore
index 70fcfb3..7259568 100644
--- a/.gitignore
+++ b/.gitignore
@@ -23,11 +23,5 @@ ltmain.sh
 missing
 network-manager-netbook.css
 org.moblin.UX.Shell.Panels.network.service
-POTFILES
-po/*.gmo
-shave
-shave-libtool
-src/marshallers/nma-marshal.[ch]
-src/network-manager-netbook
 stamp-*
 TAGS
diff --git a/Makefile.am b/Makefile.am
index 909e9ad..521009a 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,4 +1,4 @@
-SUBDIRS = icons src po
+SUBDIRS = icons marshallers libnm-gtk src po
 
 autostartdir = $(sysconfdir)/xdg/autostart
 autostart_DATA = network-manager-netbook.desktop
diff --git a/configure.in b/configure.in
index 9d42df8..d7b5abd 100644
--- a/configure.in
+++ b/configure.in
@@ -24,6 +24,8 @@ AM_GLIB_GNU_GETTEXT
 
 NM_REQUIRED=0.7.996
 
+PKG_CHECK_MODULES(LIBNM_GTK, gtk+-2.0 gconf-2.0 gnome-keyring-1 libnm-util >= $NM_REQUIRED libnm-glib >= $NM_REQUIRED)
+
 PKG_CHECK_MODULES(NMN, dbus-glib-1 >= 0.75 gtk+-2.0 gconf-2.0 gnome-keyring-1 libnotify libnm-util >= $NM_REQUIRED libnm-glib >= $NM_REQUIRED mobile-broadband-provider-info moblin-panel nbtk-gtk-1.2)
 
 GLIB_GENMARSHAL=`pkg-config --variable=glib_genmarshal glib-2.0`
@@ -35,10 +37,10 @@ icons/Makefile
 icons/22/Makefile
 icons/32/Makefile
 icons/48/Makefile
+libnm-gtk/Makefile
+libnm-gtk/wireless-security/Makefile
 po/Makefile.in
-src/marshallers/Makefile
-src/gconf-helpers/Makefile
-src/wireless-security/Makefile
+marshallers/Makefile
 src/Makefile
 ])
 AC_OUTPUT
diff --git a/libnm-gtk/.gitignore b/libnm-gtk/.gitignore
new file mode 100644
index 0000000..9d0f16a
--- /dev/null
+++ b/libnm-gtk/.gitignore
@@ -0,0 +1 @@
+libnm-gtk-test
diff --git a/libnm-gtk/Makefile.am b/libnm-gtk/Makefile.am
new file mode 100644
index 0000000..2b5ca7e
--- /dev/null
+++ b/libnm-gtk/Makefile.am
@@ -0,0 +1,95 @@
+SUBDIRS = wireless-security
+
+NULL=
+
+noinst_LTLIBRARIES = libnm-gtk.la
+
+libnm_gtk_la_CPPFLAGS = \
+	-DUIDIR=\""$(uidir)"\" \
+	-DICONDIR=\""$(pkgdatadir)/icons"\" \
+	$(LIBNM_GTK_CFLAGS) \
+	-I${top_builddir}/marshallers \
+	-I${top_srcdir}/libnm-gtk/wireless-security \
+	$(NULL)
+
+libnm_gtk_la_LIBADD = \
+	$(LIBNM_GTK_LIBS) \
+	${top_builddir}/marshallers/libmarshallers.la \
+	${top_builddir}/libnm-gtk/wireless-security/libwireless-security.la \
+	$(NULL)
+
+libnmincludedir = $(includedir)/libnm-gtk
+
+libnminclude_HEADERS = \
+	nm-cdma-item.h \
+	nm-cdma-provider.h \
+	nm-connection-item.h \
+	nm-connection-list.h \
+	nm-connection-model.h \
+	nm-device-handler.h \
+	nm-device-item.h \
+	nm-device-model.h \
+	nm-device-provider.h \
+	nm-ethernet-item.h \
+	nm-ethernet-provider.h \
+	nm-gconf-connection.h \
+	nm-gconf-settings.h \
+	nm-gsm-item.h \
+	nm-gsm-provider.h \
+	nm-item-provider.h \
+	nm-list-item.h \
+	nm-list-model.h \
+	nm-status-icon.h \
+	nm-status-model.h \
+	nm-wifi-item.h \
+	nm-wifi-provider.h \
+	$(NULL)
+
+libnm_gtk_la_SOURCES = \
+	gconf-helpers.c \
+	gconf-helpers.h \
+	gconf-upgrade.c	\
+	gconf-upgrade.h \
+	nm-cdma-item.c \
+	nm-cdma-provider.c \
+	nm-connection-item.c \
+	nm-connection-list.c \
+	nm-connection-model.c \
+	nm-device-handler.c \
+	nm-device-item.c \
+	nm-device-model.c \
+	nm-device-provider.c \
+	nm-ethernet-item.c \
+	nm-ethernet-provider.c \
+	nm-gconf-connection.c \
+	nm-gconf-settings.c \
+	nm-gsm-item.c \
+	nm-gsm-provider.c \
+	nm-icon-cache.c \
+	nm-icon-cache.h \
+	nm-item-provider.c \
+	nm-list-item.c \
+	nm-list-model.c \
+	nm-status-icon.c \
+	nm-status-model.c \
+	nm-wifi-item.c \
+	nm-wifi-provider.c \
+	utils.c \
+	utils.h \
+	wireless-dialog.c \
+	wireless-dialog.h \
+	wireless-helper.h \
+	$(NULL)
+
+noinst_PROGRAMS = libnm-gtk-test
+
+libnm_gtk_test_SOURCES = test.c
+libnm_gtk_test_CFLAGS = $(LIBNM_GTK_CFLAGS)
+libnm_gtk_test_LDADD = libnm-gtk.la $(LIBNM_GTK_LIBS)
+
+uidir = $(datadir)/network-manager-netbook
+ui_DATA = wireless-security.ui
+
+EXTRA_DIST = \
+	$(ui_DATA) \
+	$(NULL)
diff --git a/src/gconf-helpers/gconf-helpers.c b/libnm-gtk/gconf-helpers.c
similarity index 98%
rename from src/gconf-helpers/gconf-helpers.c
rename to libnm-gtk/gconf-helpers.c
index 06b2a55..bc2700d 100644
--- a/src/gconf-helpers/gconf-helpers.c
+++ b/libnm-gtk/gconf-helpers.c
@@ -21,6 +21,7 @@
  */
 
 #include <string.h>
+#include <stdio.h>
 #include <stdlib.h>
 #include <errno.h>
 #include <net/ethernet.h>
@@ -50,7 +51,8 @@
 #include "gconf-helpers.h"
 #include "gconf-upgrade.h"
 #include "utils.h"
-#include "nmn-applet.h"
+
+#define APPLET_PREFS_PATH "/apps/nm-applet"
 
 #define DBUS_TYPE_G_ARRAY_OF_OBJECT_PATH    (dbus_g_type_get_collection ("GPtrArray", DBUS_TYPE_G_OBJECT_PATH))
 #define DBUS_TYPE_G_ARRAY_OF_STRING         (dbus_g_type_get_collection ("GPtrArray", G_TYPE_STRING))
@@ -2466,8 +2468,8 @@ remove_leftovers (CopyOneSettingValueInfo *info)
 	g_slist_free (dirs);
 }
 
-void
-nm_gconf_write_connection (NMConnection *connection,
+static void
+write_connection_internal (NMConnection *connection,
                            GConfClient *client,
                            const char *dir)
 {
@@ -2506,6 +2508,41 @@ nm_gconf_write_connection (NMConnection *connection,
 	nm_gconf_set_ignore_ca_cert (info.connection_uuid, TRUE, ignore);
 }
 
+void
+nm_gconf_write_connection (NMConnection *connection,
+                           GConfClient *client,
+                           const char *dir)
+{
+	GConfClient *my_client;
+	char *my_dir;
+
+	g_return_if_fail (NM_IS_CONNECTION (connection));
+
+	my_client = client ? g_object_ref (client) : gconf_client_get_default ();
+
+	if (dir)
+		my_dir = g_strdup (dir);
+	else {
+		int i;
+
+		/* Find free GConf directory */
+		while (i++ < G_MAXUINT32) {
+			char buf[255];
+
+			snprintf (&buf[0], 255, GCONF_PATH_CONNECTIONS"/%d", i);
+			if (!gconf_client_dir_exists (my_client, buf, NULL)) {
+				my_dir = g_strdup (buf);
+				break;
+			}
+		}
+	}
+
+	write_connection_internal (connection, my_client, my_dir);
+	gconf_client_suggest_sync (my_client, NULL);
+	g_object_unref (my_client);
+	g_free (my_dir);
+}
+
 static char *
 get_ignore_path (const char *uuid, gboolean phase2)
 {
diff --git a/src/gconf-helpers/gconf-helpers.h b/libnm-gtk/gconf-helpers.h
similarity index 99%
rename from src/gconf-helpers/gconf-helpers.h
rename to libnm-gtk/gconf-helpers.h
index 17d1ce8..87889f9 100644
--- a/src/gconf-helpers/gconf-helpers.h
+++ b/libnm-gtk/gconf-helpers.h
@@ -27,7 +27,7 @@
 #include <glib.h>
 #include <nm-connection.h>
 
-#include "nma-gconf-connection.h"
+#include "nm-gconf-connection.h"
 
 #define GCONF_PATH_CONNECTIONS "/system/networking/connections"
 
diff --git a/src/gconf-helpers/gconf-upgrade.c b/libnm-gtk/gconf-upgrade.c
similarity index 100%
rename from src/gconf-helpers/gconf-upgrade.c
rename to libnm-gtk/gconf-upgrade.c
diff --git a/src/gconf-helpers/gconf-upgrade.h b/libnm-gtk/gconf-upgrade.h
similarity index 100%
rename from src/gconf-helpers/gconf-upgrade.h
rename to libnm-gtk/gconf-upgrade.h
diff --git a/libnm-gtk/nm-cdma-item.c b/libnm-gtk/nm-cdma-item.c
new file mode 100644
index 0000000..8e479a5
--- /dev/null
+++ b/libnm-gtk/nm-cdma-item.c
@@ -0,0 +1,76 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2009 Novell, Inc.
+ */
+
+#include <glib/gi18n.h>
+#include <nm-setting-8021x.h>
+#include "nm-cdma-item.h"
+
+G_DEFINE_TYPE (NMCdmaItem, nm_cdma_item, NM_TYPE_DEVICE_ITEM)
+
+NMListItem *
+nm_cdma_item_new (NMClient *client,
+                  NMCdmaDevice *device,
+                  NMSettingsConnectionInterface *connection)
+{
+    g_return_val_if_fail (NM_IS_CLIENT (client), NULL);
+    g_return_val_if_fail (NM_IS_CDMA_DEVICE (device), NULL);
+    g_return_val_if_fail (NM_IS_SETTINGS_CONNECTION_INTERFACE (connection), NULL);
+
+    return (NMListItem *) g_object_new (NM_TYPE_CDMA_ITEM,
+                                        NM_LIST_ITEM_TYPE_NAME, _("3G"),
+                                        NM_CONNECTION_ITEM_CLIENT, client,
+                                        NM_CONNECTION_ITEM_CONNECTION, connection,
+                                        NM_DEVICE_ITEM_DEVICE, device,
+                                        NULL);
+}
+
+static int
+priority (NMListItem *item)
+{
+    return NM_LIST_ITEM_PRIORITY_DEV_CDMA + NM_LIST_ITEM_CLASS (nm_cdma_item_parent_class)->priority (item);
+}
+
+/*****************************************************************************/
+
+static void
+notify (GObject *object, GParamSpec *spec)
+{
+    /* If the connection is removed from the item, request deletion */
+    if (spec && !g_strcmp0 (spec->name, NM_CONNECTION_ITEM_CONNECTION) && 
+        !nm_connection_item_get_connection (NM_CONNECTION_ITEM (object)))
+
+        nm_list_item_request_remove (NM_LIST_ITEM (object));
+}
+
+static void
+nm_cdma_item_init (NMCdmaItem *self)
+{
+    g_object_set (self, NM_LIST_ITEM_ICON, "nm-device-wwan", NULL);
+}
+
+static void
+nm_cdma_item_class_init (NMCdmaItemClass *klass)
+{
+    GObjectClass *object_class = G_OBJECT_CLASS (klass);
+    NMListItemClass *list_class = NM_LIST_ITEM_CLASS (klass);
+
+    object_class->notify = notify;
+
+    list_class->priority = priority;
+}
diff --git a/libnm-gtk/nm-cdma-item.h b/libnm-gtk/nm-cdma-item.h
new file mode 100644
index 0000000..f58ed70
--- /dev/null
+++ b/libnm-gtk/nm-cdma-item.h
@@ -0,0 +1,52 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2009 Novell, Inc.
+ */
+
+#ifndef NM_CDMA_ITEM_H
+#define NM_CDMA_ITEM_H
+
+#include <glib-object.h>
+#include <nm-cdma-device.h>
+#include <nm-device-item.h>
+
+G_BEGIN_DECLS
+
+#define NM_TYPE_CDMA_ITEM            (nm_cdma_item_get_type ())
+#define NM_CDMA_ITEM(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_CDMA_ITEM, NMCdmaItem))
+#define NM_CDMA_ITEM_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_CDMA_ITEM, NMCdmaItemClass))
+#define NM_IS_CDMA_ITEM(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_CDMA_ITEM))
+#define NM_IS_CDMA_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NM_TYPE_CDMA_ITEM))
+#define NM_CDMA_ITEM_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_CDMA_ITEM, NMCdmaItemClass))
+
+typedef struct {
+    NMDeviceItem parent;
+} NMCdmaItem;
+
+typedef struct {
+    NMDeviceItemClass parent_class;
+} NMCdmaItemClass;
+
+GType nm_cdma_item_get_type (void);
+
+NMListItem *nm_cdma_item_new (NMClient *client,
+                              NMCdmaDevice *device,
+                              NMSettingsConnectionInterface *connection);
+
+G_END_DECLS
+
+#endif /* NM_CDMA_ITEM_H */
diff --git a/libnm-gtk/nm-cdma-provider.c b/libnm-gtk/nm-cdma-provider.c
new file mode 100644
index 0000000..f3bc4d8
--- /dev/null
+++ b/libnm-gtk/nm-cdma-provider.c
@@ -0,0 +1,71 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2009 Novell, Inc.
+ */
+
+#include "nm-cdma-provider.h"
+#include "nm-cdma-item.h"
+#include "utils.h"
+
+G_DEFINE_TYPE (NMCdmaProvider, nm_cdma_provider, NM_TYPE_DEVICE_PROVIDER)
+
+NMItemProvider *
+nm_cdma_provider_new (NMClient *client,
+                      NMCdmaDevice *device)
+{
+    g_return_val_if_fail (NM_IS_CLIENT (client), NULL);
+    g_return_val_if_fail (NM_IS_CDMA_DEVICE (device), NULL);
+
+    return (NMItemProvider *) g_object_new (NM_TYPE_CDMA_PROVIDER,
+                                            NM_ITEM_PROVIDER_CLIENT, client,
+                                            NM_DEVICE_PROVIDER_DEVICE, device,
+                                            NULL);
+}
+
+static void
+cdma_added (NMItemProvider *provider,
+            NMSettingsConnectionInterface *connection)
+{
+    NMDeviceProvider *device_provider = NM_DEVICE_PROVIDER (provider);
+    NMDevice *device;
+
+    if (!nm_device_provider_ready (device_provider))
+        return;
+
+    device = nm_device_provider_get_device (device_provider);
+    if (utils_connection_valid_for_device (NM_CONNECTION (connection), device, NULL)) {
+        NMListItem *item;
+
+        item = nm_cdma_item_new (nm_item_provider_get_client (provider), NM_CDMA_DEVICE (device), connection);
+        nm_item_provider_item_added (provider, item);
+    }
+}
+
+/*****************************************************************************/
+
+static void
+nm_cdma_provider_init (NMCdmaProvider *self)
+{
+}
+
+static void
+nm_cdma_provider_class_init (NMCdmaProviderClass *klass)
+{
+    NMItemProviderClass *item_class = NM_ITEM_PROVIDER_CLASS (klass);
+
+    item_class->connection_added = cdma_added;
+}
diff --git a/libnm-gtk/nm-cdma-provider.h b/libnm-gtk/nm-cdma-provider.h
new file mode 100644
index 0000000..57f9d81
--- /dev/null
+++ b/libnm-gtk/nm-cdma-provider.h
@@ -0,0 +1,51 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2009 Novell, Inc.
+ */
+
+#ifndef NM_CDMA_PROVIDER_H
+#define NM_CDMA_PROVIDER_H
+
+#include <glib-object.h>
+#include <nm-cdma-device.h>
+#include <nm-device-provider.h>
+
+G_BEGIN_DECLS
+
+#define NM_TYPE_CDMA_PROVIDER            (nm_cdma_provider_get_type ())
+#define NM_CDMA_PROVIDER(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_CDMA_PROVIDER, NMCdmaProvider))
+#define NM_CDMA_PROVIDER_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_CDMA_PROVIDER, NMCdmaProviderClass))
+#define NM_IS_CDMA_PROVIDER(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_CDMA_PROVIDER))
+#define NM_IS_CDMA_PROVIDER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NM_TYPE_CDMA_PROVIDER))
+#define NM_CDMA_PROVIDER_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_CDMA_PROVIDER, NMCdmaProviderClass))
+
+typedef struct {
+    NMDeviceProvider parent;
+} NMCdmaProvider;
+
+typedef struct {
+    NMDeviceProviderClass parent_class;
+} NMCdmaProviderClass;
+
+GType nm_cdma_provider_get_type (void);
+
+NMItemProvider *nm_cdma_provider_new (NMClient *client,
+                                      NMCdmaDevice *device);
+
+G_END_DECLS
+
+#endif /* NM_CDMA_PROVIDER_H */
diff --git a/libnm-gtk/nm-connection-item.c b/libnm-gtk/nm-connection-item.c
new file mode 100644
index 0000000..8b55e19
--- /dev/null
+++ b/libnm-gtk/nm-connection-item.c
@@ -0,0 +1,371 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2009 Novell, Inc.
+ */
+
+#include <string.h>
+#include <nm-setting-connection.h>
+#include <nm-settings-connection-interface.h>
+#include <nm-active-connection.h>
+#include "nm-connection-item.h"
+#include "gconf-helpers.h"
+
+G_DEFINE_TYPE (NMConnectionItem, nm_connection_item, NM_TYPE_LIST_ITEM)
+
+enum {
+    PROP_0,
+    PROP_CLIENT,
+    PROP_CONNECTION,
+
+    LAST_PROP
+};
+
+#define GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), NM_TYPE_CONNECTION_ITEM, NMConnectionItemPrivate))
+
+typedef struct {
+    NMClient *client;
+    NMSettingsConnectionInterface *connection;
+    NMActiveConnection *ac;
+    gboolean connect_pending;
+
+    gulong removed_id;
+    gulong updated_id;
+    gulong acs_changed_id;
+    gulong ac_state_changed_id;
+
+    gboolean disposed;
+} NMConnectionItemPrivate;
+
+NMClient *
+nm_connection_item_get_client (NMConnectionItem *self)
+{
+    g_return_val_if_fail (NM_IS_CONNECTION_ITEM (self), NULL);
+
+    return GET_PRIVATE (self)->client;
+}
+
+NMSettingsConnectionInterface *
+nm_connection_item_get_connection (NMConnectionItem *self)
+{
+    g_return_val_if_fail (NM_IS_CONNECTION_ITEM (self), NULL);
+
+    return GET_PRIVATE (self)->connection;
+}
+
+static void
+connection_removed (NMSettingsConnectionInterface *connection,
+                    gpointer data)
+{
+    g_debug ("Connection %p removed", connection);
+    nm_connection_item_set_connection (NM_CONNECTION_ITEM (data), NULL);
+}
+
+static void
+connection_updated (NMSettingsConnectionInterface *connection,
+                    GHashTable *new_settings,
+                    gpointer data)
+{
+    NMConnectionItem *self = NM_CONNECTION_ITEM (data);
+    NMSettingConnection *s_con;
+
+    s_con = (NMSettingConnection *) nm_connection_get_setting (NM_CONNECTION (connection), NM_TYPE_SETTING_CONNECTION);
+    g_object_set (self, NM_LIST_ITEM_NAME, nm_setting_connection_get_id (s_con), NULL);
+}
+
+static void
+ac_state_changed (NMActiveConnection *ac,
+                  GParamSpec *pspec,
+                  gpointer user_data)
+{
+    NMListItem *item = NM_LIST_ITEM (user_data);
+    NMListItemStatus status;
+
+    if (ac) {
+        switch (nm_active_connection_get_state (ac)) {
+        case NM_ACTIVE_CONNECTION_STATE_ACTIVATED:
+            status = NM_LIST_ITEM_STATUS_CONNECTED;
+            break;
+        case NM_ACTIVE_CONNECTION_STATE_ACTIVATING:
+            status = NM_LIST_ITEM_STATUS_CONNECTING;
+            break;
+        default:
+            status = NM_LIST_ITEM_STATUS_DISCONNECTED;
+            break;
+        }
+    } else
+        status = NM_LIST_ITEM_STATUS_DISCONNECTED;
+
+    if (status != nm_list_item_get_status (item))
+        g_object_set (G_OBJECT (item), NM_LIST_ITEM_STATUS, status, NULL);
+}
+
+static void
+set_active_connection (NMConnectionItem *self,
+                       NMActiveConnection *ac)
+{
+    NMConnectionItemPrivate *priv = GET_PRIVATE (self);
+
+    if (priv->ac) {
+        g_signal_handler_disconnect (priv->ac, priv->ac_state_changed_id);
+        g_object_unref (priv->ac);
+    }
+
+    if (ac) {
+        priv->ac = g_object_ref (ac);
+        priv->ac_state_changed_id = g_signal_connect (priv->ac, "notify::" NM_ACTIVE_CONNECTION_STATE,
+                                                      G_CALLBACK (ac_state_changed), self);
+    } else {
+        priv->ac_state_changed_id = 0;
+        priv->ac = NULL;
+    }
+
+    ac_state_changed (ac, NULL, self);
+}
+
+static void
+active_connections_changed (NMClient *client,
+                            GParamSpec *pspec,
+                            gpointer user_data)
+{
+    NMConnectionItem *self = NM_CONNECTION_ITEM (user_data);
+    NMConnectionItemPrivate *priv = GET_PRIVATE (self);
+    NMConnection *connection;
+    const GPtrArray *acs;
+    const char *path;
+    NMActiveConnection *ac = NULL;
+    NMConnectionScope scope;
+    int i;
+
+    if (!priv->connection)
+        return;
+
+    connection = NM_CONNECTION (nm_connection_item_get_connection (self));
+    path = nm_connection_get_path (connection);
+    scope = nm_connection_get_scope (connection);
+
+    acs = nm_client_get_active_connections (client);
+    for (i = 0; acs && i < acs->len; i++) {
+        ac = g_ptr_array_index (acs, i);
+
+        if (scope == nm_active_connection_get_scope (ac) && !strcmp (path, nm_active_connection_get_connection (ac)))
+            break;
+
+        ac = NULL;
+    }
+
+    set_active_connection (self, ac);
+}
+
+static gboolean
+idle_connect (gpointer data)
+{
+    nm_list_item_connect (NM_LIST_ITEM (data));
+
+    return FALSE;
+}
+
+void
+nm_connection_item_set_connection (NMConnectionItem *self,
+                                   NMSettingsConnectionInterface *connection)
+{
+    NMConnectionItemPrivate *priv;
+
+    g_return_if_fail (NM_IS_CONNECTION_ITEM (self));
+
+    priv = GET_PRIVATE (self);
+
+    if (priv->connection) {
+        set_active_connection (self, NULL);
+        g_signal_handler_disconnect (priv->connection, priv->removed_id);
+        g_signal_handler_disconnect (priv->connection, priv->updated_id);
+        g_signal_handler_disconnect (priv->client, priv->acs_changed_id);
+        g_object_unref (priv->connection);
+    }
+
+    if (connection) {
+        priv->connection = g_object_ref (connection);
+
+        priv->removed_id = g_signal_connect (connection, "removed", G_CALLBACK (connection_removed), self);
+        priv->updated_id = g_signal_connect (connection, "updated", G_CALLBACK (connection_updated), self);
+        connection_updated (connection, NULL, self);
+
+        priv->acs_changed_id = g_signal_connect (priv->client, "notify::" NM_CLIENT_ACTIVE_CONNECTIONS,
+                                                 G_CALLBACK (active_connections_changed), self);
+        active_connections_changed (priv->client, NULL, self);
+    } else {
+        priv->updated_id = 0;
+        priv->acs_changed_id = 0;
+        priv->connection = NULL;
+    }
+
+    g_object_notify (G_OBJECT (self), NM_CONNECTION_ITEM_CONNECTION);
+    g_object_set (G_OBJECT (self), NM_LIST_ITEM_SHOW_DELETE, connection != NULL, NULL);
+
+    if (priv->connect_pending) {
+        priv->connect_pending = FALSE;
+
+        if (connection)
+            idle_connect (self);
+    }
+}
+
+void
+nm_connection_item_new_connection (NMConnectionItem *self,
+                                   NMConnection *connection,
+                                   gboolean connect)
+{
+    g_return_if_fail (NM_IS_CONNECTION_ITEM (self));
+    g_return_if_fail (NM_IS_CONNECTION (connection));
+
+    if (connect)
+        GET_PRIVATE (self)->connect_pending = TRUE;
+
+    nm_gconf_write_connection (connection, NULL, NULL);
+}
+
+static void
+delete_cb (NMSettingsConnectionInterface *connection,
+           GError *error,
+           gpointer user_data)
+{
+    if (error)
+        g_warning ("Could not delete connection: %s", error->message);
+}
+
+static void
+do_delete (NMListItem *item)
+{
+    NMConnectionItemPrivate *priv = GET_PRIVATE (item);
+
+    if (priv->connection)
+        nm_settings_connection_interface_delete (priv->connection, delete_cb, item);
+}
+
+static int
+priority (NMListItem *item)
+{
+    NMConnectionItemPrivate *priv = GET_PRIVATE (item);
+    int priority = 0;
+
+    if (priv->ac && nm_active_connection_get_state (priv->ac) == NM_ACTIVE_CONNECTION_STATE_ACTIVATED) {
+        if (nm_active_connection_get_default (priv->ac))
+            priority += NM_LIST_ITEM_PRIORITY_DEFAULT_ROUTE;
+
+        priority += NM_LIST_ITEM_PRIORITY_ACTIVATED;
+    }
+
+    if (priv->connection)
+        priority += NM_LIST_ITEM_PRIORITY_CONFIGURED;
+
+    priority += NM_LIST_ITEM_CLASS (nm_connection_item_parent_class)->priority (item);
+
+    return priority;
+}
+
+/*****************************************************************************/
+
+static void
+nm_connection_item_init (NMConnectionItem *self)
+{
+}
+
+static void
+set_property (GObject *object, guint prop_id,
+              const GValue *value, GParamSpec *pspec)
+{
+    NMConnectionItemPrivate *priv = GET_PRIVATE (object);
+
+    switch (prop_id) {
+    case PROP_CLIENT:
+        /* Construct only */
+        priv->client = g_value_dup_object (value);
+        break;
+    case PROP_CONNECTION:
+        nm_connection_item_set_connection (NM_CONNECTION_ITEM (object), g_value_get_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)
+{
+    NMConnectionItem *self = NM_CONNECTION_ITEM (object);
+
+    switch (prop_id) {
+    case PROP_CLIENT:
+        g_value_set_object (value, GET_PRIVATE (self)->client);
+        break;
+    case PROP_CONNECTION:
+        g_value_set_object (value, nm_connection_item_get_connection (self));
+        break;
+    default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+        break;
+    }
+}
+
+static void
+dispose (GObject *object)
+{
+    NMConnectionItem *self = NM_CONNECTION_ITEM (object);
+    NMConnectionItemPrivate *priv = GET_PRIVATE (self);
+
+    if (!priv->disposed) {
+        nm_connection_item_set_connection (self, NULL);
+        g_object_unref (priv->client);
+        priv->disposed = TRUE;
+    }
+
+    G_OBJECT_CLASS (nm_connection_item_parent_class)->dispose (object);
+}
+
+static void
+nm_connection_item_class_init (NMConnectionItemClass *klass)
+{
+    GObjectClass *object_class = G_OBJECT_CLASS (klass);
+    NMListItemClass *list_class = NM_LIST_ITEM_CLASS (klass);
+
+    g_type_class_add_private (object_class, sizeof (NMConnectionItemPrivate));
+
+    object_class->set_property = set_property;
+    object_class->get_property = get_property;
+    object_class->dispose = dispose;
+
+    list_class->delete = do_delete;
+    list_class->priority = priority;
+
+    /* Properties */
+    g_object_class_install_property
+        (object_class, PROP_CLIENT,
+         g_param_spec_object (NM_CONNECTION_ITEM_CLIENT,
+                              "NMClient",
+                              "NMClient",
+                              NM_TYPE_CLIENT,
+                              G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+    g_object_class_install_property
+        (object_class, PROP_CONNECTION,
+         g_param_spec_object (NM_CONNECTION_ITEM_CONNECTION,
+                              "Connection",
+                              "Connection",
+                              NM_TYPE_SETTINGS_CONNECTION_INTERFACE,
+                              G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+}
diff --git a/libnm-gtk/nm-connection-item.h b/libnm-gtk/nm-connection-item.h
new file mode 100644
index 0000000..d9fc599
--- /dev/null
+++ b/libnm-gtk/nm-connection-item.h
@@ -0,0 +1,61 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2009 Novell, Inc.
+ */
+
+#ifndef NM_CONNECTION_ITEM_H
+#define NM_CONNECTION_ITEM_H
+
+#include <glib-object.h>
+#include <nm-client.h>
+#include <nm-settings-connection-interface.h>
+#include <nm-list-item.h>
+
+G_BEGIN_DECLS
+
+#define NM_TYPE_CONNECTION_ITEM            (nm_connection_item_get_type ())
+#define NM_CONNECTION_ITEM(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_CONNECTION_ITEM, NMConnectionItem))
+#define NM_CONNECTION_ITEM_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_CONNECTION_ITEM, NMConnectionItemClass))
+#define NM_IS_CONNECTION_ITEM(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_CONNECTION_ITEM))
+#define NM_IS_CONNECTION_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NM_TYPE_CONNECTION_ITEM))
+#define NM_CONNECTION_ITEM_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_CONNECTION_ITEM, NMConnectionItemClass))
+
+#define NM_CONNECTION_ITEM_CLIENT     "client"
+#define NM_CONNECTION_ITEM_CONNECTION "connection"
+
+typedef struct {
+    NMListItem parent;
+} NMConnectionItem;
+
+typedef struct {
+    NMListItemClass parent_class;
+} NMConnectionItemClass;
+
+GType nm_connection_item_get_type (void);
+
+NMClient                      *nm_connection_item_get_client     (NMConnectionItem *self);
+NMSettingsConnectionInterface *nm_connection_item_get_connection (NMConnectionItem *self);
+void                           nm_connection_item_set_connection (NMConnectionItem *self,
+                                                                  NMSettingsConnectionInterface *connection);
+
+void                           nm_connection_item_new_connection (NMConnectionItem *self,
+                                                                  NMConnection *connection,
+                                                                  gboolean connect);
+
+G_END_DECLS
+
+#endif /* NM_CONNECTION_ITEM_H */
diff --git a/libnm-gtk/nm-connection-list.c b/libnm-gtk/nm-connection-list.c
new file mode 100644
index 0000000..29065d1
--- /dev/null
+++ b/libnm-gtk/nm-connection-list.c
@@ -0,0 +1,276 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2009 Novell, Inc.
+ */
+
+#include "nm-connection-list.h"
+
+G_DEFINE_TYPE (NMConnectionList, nm_connection_list, GTK_TYPE_LIST_STORE)
+
+enum {
+    PROP_0,
+    PROP_CLIENT,
+
+    LAST_PROP
+};
+
+#define GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), NM_TYPE_CONNECTION_LIST, NMConnectionListPrivate))
+
+typedef struct {
+    NMClient *client;
+    GSList *settings;
+
+    gboolean disposed;
+} NMConnectionListPrivate;
+
+GtkTreeModel *
+nm_connection_list_new (NMClient *client)
+{
+    g_return_val_if_fail (NM_IS_CLIENT (client), NULL);
+
+    return (GtkTreeModel *) g_object_new (NM_TYPE_CONNECTION_LIST,
+                                          NM_CONNECTION_LIST_CLIENT, client,
+                                          NULL);
+}
+
+/* Connection handling */
+
+static void
+connection_updated (NMSettingsConnectionInterface *connection,
+                    GHashTable *new_settings,
+                    gpointer data)
+{
+    g_debug ("Connection %p updated", connection);
+}
+
+static void
+connection_removed (NMSettingsConnectionInterface *connection,
+                    gpointer data)
+{
+    g_debug ("Connection %p removed", connection);
+    g_signal_handlers_disconnect_matched (connection, G_SIGNAL_MATCH_DATA,
+                                          0, 0, NULL, NULL, data);
+}
+
+static void
+connection_added (NMSettingsInterface *settings,
+                  NMSettingsConnectionInterface *connection,
+                  gpointer data)
+{
+    g_debug ("Connection %p added", connection);
+
+    g_signal_connect (connection, "updated", G_CALLBACK (connection_updated), data);
+    g_signal_connect (connection, "removed", G_CALLBACK (connection_removed), data);
+}
+
+static void
+connection_handling_cleanup (NMConnectionList *self)
+{
+    NMConnectionListPrivate *priv = GET_PRIVATE (self);
+    GSList *iter;
+
+    g_debug ("Cleaning up settings");
+
+    for (iter = priv->settings; iter; iter = iter->next) {
+        NMSettingsInterface *settings = NM_SETTINGS_INTERFACE (iter->data);
+        GSList *connections;
+        GSList *connection_iter;
+
+        connections = nm_settings_interface_list_connections (settings);
+        for (connection_iter = connections; connection_iter; connection_iter = connection_iter->next)
+            connection_removed (NM_SETTINGS_CONNECTION_INTERFACE (connection_iter->data), self);
+
+        g_slist_free (connections);
+
+        g_signal_handlers_disconnect_matched (settings, G_SIGNAL_MATCH_DATA,
+                                              0, 0, NULL, NULL, self);
+        g_object_unref (settings);
+    }
+
+    g_slist_free (priv->settings);
+}
+
+/* Device handling */
+
+static void
+device_state_changed (NMDevice *device,
+                      NMDeviceState new_state,
+                      NMDeviceState old_state,
+                      NMDeviceStateReason reason)
+{
+    g_debug ("device state %s changed (%d)", nm_device_get_iface (device), new_state);
+}
+
+static void
+device_added (NMClient *client,
+              NMDevice *device,
+              gpointer user_data)
+{
+    g_debug ("device %s added", nm_device_get_iface (device));
+
+    g_signal_connect (device, "state-changed", G_CALLBACK (device_state_changed), user_data);
+}
+
+static void
+device_removed (NMClient *client,
+                NMDevice *device,
+                gpointer user_data)
+{
+    g_debug ("device %s removed", nm_device_get_iface (device));
+
+    g_signal_handlers_disconnect_matched (device, G_SIGNAL_MATCH_DATA,
+                                          0, 0, NULL, NULL, user_data);
+}
+
+static void
+device_handling_setup (NMConnectionList *self)
+{
+    NMConnectionListPrivate *priv = GET_PRIVATE (self);
+    const GPtrArray *devices;
+    int i;
+
+    g_signal_connect (priv->client, "device-added", G_CALLBACK (device_added), self);
+    g_signal_connect (priv->client, "device-removed", G_CALLBACK (device_removed), self);
+
+    devices = nm_client_get_devices (priv->client);
+    for (i = 0; devices && devices->len > i; i++)
+        device_added (priv->client, NM_DEVICE (g_ptr_array_index (devices, i)), self);
+}
+
+static void
+device_handling_cleanup (NMConnectionList *self)
+{
+    NMConnectionListPrivate *priv = GET_PRIVATE (self);
+    const GPtrArray *devices;
+    int i;
+
+    g_debug ("Cleaning up devices");
+
+    g_signal_handlers_disconnect_matched (priv->client, G_SIGNAL_MATCH_DATA,
+                                          0, 0, NULL, NULL, self);
+
+    devices = nm_client_get_devices (priv->client);
+    for (i = 0; devices && devices->len > i; i++)
+        device_removed (priv->client, NM_DEVICE (g_ptr_array_index (devices, i)), self);
+}
+
+void
+nm_connection_list_add_settings (NMConnectionList *self,
+                                 NMSettingsInterface *settings)
+{
+    NMConnectionListPrivate *priv;
+    GSList *connections;
+    GSList *iter;
+
+    g_return_if_fail (NM_IS_CONNECTION_LIST (self));
+    g_return_if_fail (NM_IS_SETTINGS_INTERFACE (settings));
+
+    priv = GET_PRIVATE (self);
+
+    if (priv->settings == NULL)
+        /* First setting, set up device handling */
+        device_handling_setup (self);
+
+    priv->settings = g_slist_prepend (priv->settings, g_object_ref (settings));
+    g_signal_connect (settings, "new-connection", G_CALLBACK (connection_added), self);
+
+    connections = nm_settings_interface_list_connections (settings);
+    for (iter = connections; iter; iter = iter->next)
+        connection_added (settings, NM_SETTINGS_CONNECTION_INTERFACE (iter->data), self);
+
+    g_slist_free (connections);
+}
+
+/*****************************************************************************/
+
+static void
+nm_connection_list_init (NMConnectionList *self)
+{
+}
+
+static void
+set_property (GObject *object, guint prop_id,
+              const GValue *value, GParamSpec *pspec)
+{
+    NMConnectionListPrivate *priv = GET_PRIVATE (object);
+
+    switch (prop_id) {
+    case PROP_CLIENT:
+        /* Construct only */
+        priv->client = 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)
+{
+    NMConnectionListPrivate *priv = GET_PRIVATE (object);
+
+    switch (prop_id) {
+    case PROP_CLIENT:
+        g_value_set_object (value, priv->client);
+        break;
+    default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+        break;
+    }
+}
+
+static void
+dispose (GObject *object)
+{
+    NMConnectionList *self = NM_CONNECTION_LIST (object);
+    NMConnectionListPrivate *priv = GET_PRIVATE (self);
+
+    if (!priv->disposed) {
+        connection_handling_cleanup (self);
+        device_handling_cleanup (self);
+
+        if (priv->client)
+            g_object_unref (priv->client);
+
+        priv->disposed = TRUE;
+    }
+
+    G_OBJECT_CLASS (nm_connection_list_parent_class)->dispose (object);
+}
+
+static void
+nm_connection_list_class_init (NMConnectionListClass *klass)
+{
+    GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+    g_type_class_add_private (object_class, sizeof (NMConnectionListPrivate));
+
+    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_CLIENT,
+         g_param_spec_object (NM_CONNECTION_LIST_CLIENT,
+                              "NMClient",
+                              "NMClient",
+                              NM_TYPE_CLIENT,
+                              G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+}
diff --git a/libnm-gtk/nm-connection-list.h b/libnm-gtk/nm-connection-list.h
new file mode 100644
index 0000000..175d6d8
--- /dev/null
+++ b/libnm-gtk/nm-connection-list.h
@@ -0,0 +1,54 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2009 Novell, Inc.
+ */
+
+#ifndef NM_CONNECTION_LIST_H
+#define NM_CONNECTION_LIST_H
+
+#include <gtk/gtk.h>
+#include <nm-client.h>
+#include <nm-settings-interface.h>
+
+G_BEGIN_DECLS
+
+#define NM_TYPE_CONNECTION_LIST            (nm_connection_list_get_type ())
+#define NM_CONNECTION_LIST(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_CONNECTION_LIST, NMConnectionList))
+#define NM_CONNECTION_LIST_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_CONNECTION_LIST, NMConnectionListClass))
+#define NM_IS_CONNECTION_LIST(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_CONNECTION_LIST))
+#define NM_IS_CONNECTION_LIST_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NM_TYPE_CONNECTION_LIST))
+#define NM_CONNECTION_LIST_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_CONNECTION_LIST, NMConnectionListClass))
+
+#define NM_CONNECTION_LIST_CLIENT "client"
+
+typedef struct {
+    GtkListStore parent;
+} NMConnectionList;
+
+typedef struct {
+    GtkListStoreClass parent_class;
+} NMConnectionListClass;
+
+GType nm_connection_list_get_type (void);
+
+GtkTreeModel *nm_connection_list_new          (NMClient *client);
+void          nm_connection_list_add_settings (NMConnectionList *self,
+                                               NMSettingsInterface *settings);
+
+G_END_DECLS
+
+#endif /* NM_CONNECTION_LIST_H */
diff --git a/libnm-gtk/nm-connection-model.c b/libnm-gtk/nm-connection-model.c
new file mode 100644
index 0000000..e84e17c
--- /dev/null
+++ b/libnm-gtk/nm-connection-model.c
@@ -0,0 +1,203 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2009 Novell, Inc.
+ */
+
+#include <nm-setting-connection.h>
+#include "nm-connection-model.h"
+
+G_DEFINE_TYPE (NMConnectionModel, nm_connection_model, GTK_TYPE_LIST_STORE)
+
+#define GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), NM_TYPE_CONNECTION_MODEL, NMConnectionModelPrivate))
+
+typedef struct {
+    GSList *settings;
+
+    gboolean disposed;
+} NMConnectionModelPrivate;
+
+static GQuark quark_item_iter = 0;
+
+GtkTreeModel *
+nm_connection_model_new (void)
+{
+    return (GtkTreeModel *) g_object_new (NM_TYPE_CONNECTION_MODEL, NULL);
+}
+
+static void
+update_iter (GtkListStore *store,
+             GtkTreeIter *iter,
+             NMSettingsConnectionInterface *connection)
+{
+    NMSettingConnection *s_con;
+
+    s_con = (NMSettingConnection *) nm_connection_get_setting (NM_CONNECTION (connection),
+                                                               NM_TYPE_SETTING_CONNECTION);
+    g_return_if_fail (s_con != NULL);
+
+    gtk_list_store_set (store, iter,
+                        NM_CONNECTION_MODEL_COL_CONNECTION, connection,
+                        NM_CONNECTION_MODEL_COL_NAME,       nm_setting_connection_get_id (s_con),
+                        NM_CONNECTION_MODEL_COL_TYPE,       nm_setting_connection_get_connection_type (s_con),
+                        -1);
+}
+
+static void
+connection_updated (NMSettingsConnectionInterface *connection,
+                    GHashTable *new_settings,
+                    gpointer user_data)
+{
+    GtkTreeIter *iter;
+
+    iter = (GtkTreeIter *) g_object_get_qdata (G_OBJECT (connection), quark_item_iter);
+    if (iter)
+        update_iter (GTK_LIST_STORE (user_data), iter, connection);
+}
+
+static void
+connection_removed (NMSettingsConnectionInterface *connection,
+                    gpointer user_data)
+{
+    GtkListStore *store = GTK_LIST_STORE (user_data);
+    GtkTreeIter *iter;
+
+    g_signal_handlers_disconnect_by_func (connection, connection_updated, user_data);
+    g_signal_handlers_disconnect_by_func (connection, connection_removed, user_data);
+
+    iter = (GtkTreeIter *) g_object_get_qdata (G_OBJECT (connection), quark_item_iter);
+    if (iter) {
+        gtk_list_store_remove (store, iter);
+        g_object_set_qdata (G_OBJECT (connection), quark_item_iter, NULL);
+    }
+}
+
+static void
+connection_added (NMSettingsInterface *settings,
+                  NMSettingsConnectionInterface *connection,
+                  gpointer user_data)
+{
+    GtkListStore *store = GTK_LIST_STORE (user_data);
+    GtkTreeIter *iter;
+
+    iter = g_slice_new0 (GtkTreeIter);
+
+    gtk_list_store_append (store, iter);
+    update_iter (store, iter, connection);
+
+    g_object_set_qdata_full (G_OBJECT (connection), quark_item_iter, iter, (GDestroyNotify) gtk_tree_iter_free);
+    g_signal_connect (connection, "updated", G_CALLBACK (connection_updated), user_data);
+    g_signal_connect (connection, "removed", G_CALLBACK (connection_removed), user_data);
+}
+
+void
+nm_connection_model_add_settings (NMConnectionModel *self,
+                                  NMSettingsInterface *settings)
+{
+    NMConnectionModelPrivate *priv;
+    GSList *items;
+    GSList *iter;
+
+    g_return_if_fail (NM_IS_CONNECTION_MODEL (self));
+    g_return_if_fail (NM_IS_SETTINGS_INTERFACE (settings));
+
+    priv = GET_PRIVATE (self);
+    priv->settings = g_slist_append (priv->settings, g_object_ref (settings));
+    g_signal_connect (settings, "new-connection", G_CALLBACK (connection_added), self);
+
+    items = nm_settings_interface_list_connections (settings);
+    for (iter = items; iter; iter = iter->next)
+        connection_added (settings, NM_SETTINGS_CONNECTION_INTERFACE (iter->data), self);
+
+    g_slist_free (items);
+}
+
+#if 0
+static int
+sort_callback (GtkTreeModel *model,
+               GtkTreeIter *a,
+               GtkTreeIter *b,
+               gpointer user_data)
+{
+    GValue value_a = {0, };
+    GValue value_b = {0, };
+    int result;
+
+    gtk_tree_model_get_value (model, a, NM_CONNECTION_MODEL_COL_ITEM, &value_a);
+    gtk_tree_model_get_value (model, b, NM_CONNECTION_MODEL_COL_ITEM, &value_b);
+
+    result = nm_list_item_compare (NM_LIST_ITEM (g_value_get_object (&value_a)),
+                                   NM_LIST_ITEM (g_value_get_object (&value_b)));
+
+    g_value_unset (&value_a);
+    g_value_unset (&value_b);
+
+    return result;
+}
+#endif
+
+/*****************************************************************************/
+
+static void
+nm_connection_model_init (NMConnectionModel *self)
+{
+    GType types[NM_CONNECTION_MODEL_N_COLUMNS];
+
+    types[NM_CONNECTION_MODEL_COL_CONNECTION] = NM_TYPE_SETTINGS_CONNECTION_INTERFACE;
+    types[NM_CONNECTION_MODEL_COL_NAME]       = G_TYPE_STRING;
+    types[NM_CONNECTION_MODEL_COL_TYPE]       = G_TYPE_STRING;
+
+    gtk_list_store_set_column_types (GTK_LIST_STORE (self), NM_CONNECTION_MODEL_N_COLUMNS, types);
+
+#if 0
+    gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (self),
+                                     NM_CONNECTION_MODEL_COL_ITEM,
+                                     sort_callback,
+                                     NULL,
+                                     NULL);
+
+    gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (self), NM_CONNECTION_MODEL_COL_ITEM, GTK_SORT_ASCENDING);
+#endif
+}
+
+static void
+dispose (GObject *object)
+{
+    NMConnectionModelPrivate *priv = GET_PRIVATE (object);
+
+    if (!priv->disposed) {
+        if (priv->settings) {
+            g_slist_foreach (priv->settings, (GFunc) g_object_unref, NULL);
+            g_slist_free (priv->settings);
+        }
+
+        priv->disposed = TRUE;
+    }
+
+    G_OBJECT_CLASS (nm_connection_model_parent_class)->dispose (object);
+}
+
+static void
+nm_connection_model_class_init (NMConnectionModelClass *klass)
+{
+    GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+    quark_item_iter = g_quark_from_static_string ("NMConnectionModel-item-iter");
+
+    g_type_class_add_private (object_class, sizeof (NMConnectionModelPrivate));
+
+    object_class->dispose = dispose;
+}
diff --git a/libnm-gtk/nm-connection-model.h b/libnm-gtk/nm-connection-model.h
new file mode 100644
index 0000000..5d3b7a8
--- /dev/null
+++ b/libnm-gtk/nm-connection-model.h
@@ -0,0 +1,60 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2009 Novell, Inc.
+ */
+
+#ifndef NM_CONNECTION_MODEL_H
+#define NM_CONNECTION_MODEL_H
+
+#include <gtk/gtk.h>
+#include <nm-settings-interface.h>
+
+G_BEGIN_DECLS
+
+#define NM_TYPE_CONNECTION_MODEL            (nm_connection_model_get_type ())
+#define NM_CONNECTION_MODEL(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_CONNECTION_MODEL, NMConnectionModel))
+#define NM_CONNECTION_MODEL_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_CONNECTION_MODEL, NMConnectionModelClass))
+#define NM_IS_CONNECTION_MODEL(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_CONNECTION_MODEL))
+#define NM_IS_CONNECTION_MODEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NM_TYPE_CONNECTION_MODEL))
+#define NM_CONNECTION_MODEL_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_CONNECTION_MODEL, NMConnectionModelClass))
+
+enum {
+    NM_CONNECTION_MODEL_COL_CONNECTION,
+    NM_CONNECTION_MODEL_COL_NAME,
+    NM_CONNECTION_MODEL_COL_TYPE,
+
+    NM_CONNECTION_MODEL_N_COLUMNS
+};
+
+typedef struct {
+    GtkListStore parent;
+} NMConnectionModel;
+
+typedef struct {
+    GtkListStoreClass parent_class;
+} NMConnectionModelClass;
+
+GType nm_connection_model_get_type (void);
+
+GtkTreeModel *nm_connection_model_new          (void);
+void          nm_connection_model_add_settings (NMConnectionModel *self,
+                                                NMSettingsInterface *settings);
+
+
+G_END_DECLS
+
+#endif /* NM_CONNECTION_MODEL_H */
diff --git a/libnm-gtk/nm-device-handler.c b/libnm-gtk/nm-device-handler.c
new file mode 100644
index 0000000..167b9fc
--- /dev/null
+++ b/libnm-gtk/nm-device-handler.c
@@ -0,0 +1,263 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2009 Novell, Inc.
+ */
+
+#include <nm-device-ethernet.h>
+#include <nm-device-wifi.h>
+#include <nm-gsm-device.h>
+#include <nm-cdma-device.h>
+
+#include "nm-device-handler.h"
+#include "nm-ethernet-provider.h"
+#include "nm-wifi-provider.h"
+#include "nm-gsm-provider.h"
+#include "nm-cdma-provider.h"
+
+G_DEFINE_TYPE (NMDeviceHandler, nm_device_handler, G_TYPE_OBJECT)
+
+enum {
+    PROP_0,
+    PROP_CLIENT,
+
+    LAST_PROP
+};
+
+enum {
+	PROVIDER_ADDED,
+	PROVIDER_REMOVED,
+
+	LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+#define GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), NM_TYPE_DEVICE_HANDLER, NMDeviceHandlerPrivate))
+
+typedef struct {
+    NMClient *client;
+    GSList *providers;
+
+    gboolean disposed;
+} NMDeviceHandlerPrivate;
+
+
+NMDeviceHandler *
+nm_device_handler_new (NMClient *client)
+{
+    g_return_val_if_fail (NM_IS_CLIENT (client), NULL);
+
+    return (NMDeviceHandler *) g_object_new (NM_TYPE_DEVICE_HANDLER,
+                                             NM_DEVICE_HANDLER_CLIENT, client,
+                                             NULL);
+}
+
+GSList *
+nm_device_handler_get_providers (NMDeviceHandler *self)
+{
+    g_return_val_if_fail (NM_IS_DEVICE_HANDLER (self), NULL);
+
+    return GET_PRIVATE (self)->providers;
+}
+
+static NMItemProvider *
+create_provider (NMDeviceHandler *self, NMDevice *device)
+{
+    NMDeviceHandlerPrivate *priv = GET_PRIVATE (self);
+    NMItemProvider *provider;
+    GType type;
+
+    type = G_OBJECT_TYPE (device);
+
+    if (type == NM_TYPE_DEVICE_ETHERNET)
+        provider = nm_ethernet_provider_new (priv->client, NM_DEVICE_ETHERNET (device));
+    else if (type == NM_TYPE_DEVICE_WIFI)
+        provider = nm_wifi_provider_new (priv->client, NM_DEVICE_WIFI (device));
+    else if (type == NM_TYPE_GSM_DEVICE)
+        provider = nm_gsm_provider_new (priv->client, NM_GSM_DEVICE (device));
+    else if (type == NM_TYPE_CDMA_DEVICE)
+        provider = nm_cdma_provider_new (priv->client, NM_CDMA_DEVICE (device));
+    else {
+        g_warning ("Unknown device type %s", G_OBJECT_TYPE_NAME (device));
+        provider = NULL;
+    }
+
+    return provider;
+}
+
+static void
+device_added (NMClient *client,
+              NMDevice *device,
+              gpointer user_data)
+{
+    NMDeviceHandler *self = NM_DEVICE_HANDLER (user_data);
+    NMDeviceHandlerPrivate *priv = GET_PRIVATE (self);
+    NMItemProvider *provider;
+
+    g_debug ("device %s added", nm_device_get_iface (device));
+
+    provider = create_provider (self, device);
+    if (provider) {
+        priv->providers = g_slist_prepend (priv->providers, provider);
+        g_signal_emit (self, signals[PROVIDER_ADDED], 0, provider);
+    }
+}
+
+static void
+device_removed (NMClient *client,
+                NMDevice *device,
+                gpointer user_data)
+{
+    NMDeviceHandler *self = NM_DEVICE_HANDLER (user_data);
+    NMDeviceHandlerPrivate *priv = GET_PRIVATE (self);
+    GSList *iter;
+
+    g_debug ("device %s removed", nm_device_get_iface (device));
+
+    for (iter = priv->providers; iter; iter = iter->next) {
+        NMDeviceProvider *provider = (NMDeviceProvider *) iter->data;
+
+        if (nm_device_provider_get_device (provider) == device) {
+            priv->providers = g_slist_delete_link (priv->providers, iter);
+            g_signal_emit (self, signals[PROVIDER_REMOVED], 0, provider);
+            g_object_unref (provider);
+            break;
+        }
+    }
+}
+
+/*****************************************************************************/
+
+static void
+nm_device_handler_init (NMDeviceHandler *self)
+{
+}
+
+static void
+set_property (GObject *object, guint prop_id,
+              const GValue *value, GParamSpec *pspec)
+{
+    NMDeviceHandlerPrivate *priv = GET_PRIVATE (object);
+
+    switch (prop_id) {
+    case PROP_CLIENT:
+        /* Construct only */
+        priv->client = 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)
+{
+    NMDeviceHandlerPrivate *priv = GET_PRIVATE (object);
+
+    switch (prop_id) {
+    case PROP_CLIENT:
+        g_value_set_object (value, priv->client);
+        break;
+    default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+        break;
+    }
+}
+
+static void
+constructed (GObject *object)
+{
+    NMDeviceHandlerPrivate *priv = GET_PRIVATE (object);
+    const GPtrArray *devices;
+    int i;
+
+    if (G_OBJECT_CLASS (nm_device_handler_parent_class)->constructed)
+        G_OBJECT_CLASS (nm_device_handler_parent_class)->constructed (object);
+
+    g_signal_connect (priv->client, "device-added",   G_CALLBACK (device_added), object);
+    g_signal_connect (priv->client, "device-removed", G_CALLBACK (device_removed), object);
+
+    devices = nm_client_get_devices (priv->client);
+    for (i = 0; devices && devices->len > i; i++)
+        device_added (priv->client, NM_DEVICE (g_ptr_array_index (devices, i)), object);
+}
+
+static void
+dispose (GObject *object)
+{
+    NMDeviceHandlerPrivate *priv = GET_PRIVATE (object);
+    const GPtrArray *devices;
+    int i;
+
+    if (!priv->disposed) {
+        g_signal_handlers_disconnect_matched (priv->client, G_SIGNAL_MATCH_DATA,
+                                              0, 0, NULL, NULL, object);
+
+        devices = nm_client_get_devices (priv->client);
+        for (i = 0; devices && devices->len > i; i++)
+            device_removed (priv->client, NM_DEVICE (g_ptr_array_index (devices, i)), object);
+
+        priv->disposed = TRUE;
+    }
+
+    G_OBJECT_CLASS (nm_device_handler_parent_class)->dispose (object);
+}
+
+static void
+nm_device_handler_class_init (NMDeviceHandlerClass *klass)
+{
+    GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+    g_type_class_add_private (object_class, sizeof (NMDeviceHandlerPrivate));
+
+    object_class->set_property = set_property;
+    object_class->get_property = get_property;
+    object_class->constructed = constructed;
+    object_class->dispose = dispose;
+
+    /* Properties */
+    g_object_class_install_property
+        (object_class, PROP_CLIENT,
+         g_param_spec_object (NM_DEVICE_HANDLER_CLIENT,
+                              "NMClient",
+                              "NMClient",
+                              NM_TYPE_CLIENT,
+                              G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+    /* Signals */
+    signals[PROVIDER_ADDED] =
+		g_signal_new ("provider-added",
+					  G_OBJECT_CLASS_TYPE (object_class),
+					  G_SIGNAL_RUN_FIRST,
+					  G_STRUCT_OFFSET (NMDeviceHandlerClass, provider_added),
+					  NULL, NULL,
+					  g_cclosure_marshal_VOID__OBJECT,
+					  G_TYPE_NONE, 1,
+					  NM_TYPE_ITEM_PROVIDER);
+
+    signals[PROVIDER_REMOVED] =
+		g_signal_new ("provider-removed",
+					  G_OBJECT_CLASS_TYPE (object_class),
+					  G_SIGNAL_RUN_FIRST,
+					  G_STRUCT_OFFSET (NMDeviceHandlerClass, provider_removed),
+					  NULL, NULL,
+					  g_cclosure_marshal_VOID__OBJECT,
+					  G_TYPE_NONE, 1,
+					  NM_TYPE_ITEM_PROVIDER);
+}
diff --git a/libnm-gtk/nm-device-handler.h b/libnm-gtk/nm-device-handler.h
new file mode 100644
index 0000000..e33a98d
--- /dev/null
+++ b/libnm-gtk/nm-device-handler.h
@@ -0,0 +1,60 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2009 Novell, Inc.
+ */
+
+#ifndef NM_DEVICE_HANDLER_H
+#define NM_DEVICE_HANDLER_H
+
+#include <glib-object.h>
+#include <nm-client.h>
+#include <nm-item-provider.h>
+
+G_BEGIN_DECLS
+
+#define NM_TYPE_DEVICE_HANDLER            (nm_device_handler_get_type ())
+#define NM_DEVICE_HANDLER(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DEVICE_HANDLER, NMDeviceHandler))
+#define NM_DEVICE_HANDLER_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_DEVICE_HANDLER, NMDeviceHandlerClass))
+#define NM_IS_DEVICE_HANDLER(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_DEVICE_HANDLER))
+#define NM_IS_DEVICE_HANDLER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NM_TYPE_DEVICE_HANDLER))
+#define NM_DEVICE_HANDLER_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DEVICE_HANDLER, NMDeviceHandlerClass))
+
+#define NM_DEVICE_HANDLER_CLIENT "client"
+
+typedef struct {
+    GObject parent;
+} NMDeviceHandler;
+
+typedef struct {
+    GObjectClass parent_class;
+
+    /* Signals */
+    void (*provider_added) (NMDeviceHandler *self,
+                            NMItemProvider *provider);
+
+    void (*provider_removed) (NMDeviceHandler *self,
+                              NMItemProvider *provider);
+} NMDeviceHandlerClass;
+
+GType nm_device_handler_get_type (void);
+
+NMDeviceHandler *nm_device_handler_new           (NMClient *client);
+GSList          *nm_device_handler_get_providers (NMDeviceHandler *self);
+
+G_END_DECLS
+
+#endif /* NM_DEVICE_HANDLER_H */
diff --git a/libnm-gtk/nm-device-item.c b/libnm-gtk/nm-device-item.c
new file mode 100644
index 0000000..dc134bb
--- /dev/null
+++ b/libnm-gtk/nm-device-item.c
@@ -0,0 +1,176 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2009 Novell, Inc.
+ */
+
+#include "nm-device-item.h"
+
+G_DEFINE_ABSTRACT_TYPE (NMDeviceItem, nm_device_item, NM_TYPE_CONNECTION_ITEM)
+
+enum {
+    PROP_0,
+    PROP_DEVICE,
+
+    LAST_PROP
+};
+
+#define GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), NM_TYPE_DEVICE_ITEM, NMDeviceItemPrivate))
+
+typedef struct {
+    NMDevice *device;
+
+    gboolean disposed;
+} NMDeviceItemPrivate;
+
+NMDevice *
+nm_device_item_get_device (NMDeviceItem *self)
+{
+    g_return_val_if_fail (NM_IS_DEVICE_ITEM (self), NULL);
+
+    return GET_PRIVATE (self)->device;
+}
+
+static void
+connect_cb (gpointer user_data, const char *object_path, GError *error)
+{
+    if (error)
+        g_warning ("Could not activate device: %s", error->message);
+}
+
+static void
+connect (NMListItem *item)
+{
+    NMDeviceItem *self = NM_DEVICE_ITEM (item);
+    NMConnectionItem *connection_item = NM_CONNECTION_ITEM (self);
+    NMConnection *connection;
+    const char *path;
+    const char *service_name;
+    char *specific_object;
+    NMConnectionScope scope;
+
+    connection = NM_CONNECTION (nm_connection_item_get_connection (connection_item));
+    path = nm_connection_get_path (connection);
+
+    scope = nm_connection_get_scope (connection);
+    service_name = (scope == NM_CONNECTION_SCOPE_USER) ?
+        NM_DBUS_SERVICE_USER_SETTINGS : NM_DBUS_SERVICE_SYSTEM_SETTINGS;
+
+    if (NM_DEVICE_ITEM_GET_CLASS (item)->get_specific_object)
+        specific_object = NM_DEVICE_ITEM_GET_CLASS (item)->get_specific_object (self);
+    else
+        specific_object = g_strdup ("/");
+
+    nm_client_activate_connection (nm_connection_item_get_client (connection_item),
+                                   service_name, path,
+                                   nm_device_item_get_device (self),
+                                   specific_object,
+                                   connect_cb,
+                                   item);
+
+    g_free (specific_object);
+}
+
+static void
+disconnect_cb (NMDevice *device, GError *error, gpointer user_data)
+{
+    if (error)
+        g_warning ("Could not deactivate device: %s", error->message);
+}
+
+static void
+disconnect (NMListItem *item)
+{
+    nm_device_disconnect (nm_device_item_get_device (NM_DEVICE_ITEM (item)), disconnect_cb, item);
+}
+
+/*****************************************************************************/
+
+static void
+nm_device_item_init (NMDeviceItem *self)
+{
+}
+
+static void
+set_property (GObject *object, guint prop_id,
+              const GValue *value, GParamSpec *pspec)
+{
+    NMDeviceItemPrivate *priv = GET_PRIVATE (object);
+
+    switch (prop_id) {
+    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)
+{
+    NMDeviceItemPrivate *priv = GET_PRIVATE (object);
+
+    switch (prop_id) {
+    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)
+{
+    NMDeviceItemPrivate *priv = GET_PRIVATE (object);
+
+    if (!priv->disposed) {
+        g_object_unref (priv->device);
+        priv->disposed = TRUE;
+    }
+
+    G_OBJECT_CLASS (nm_device_item_parent_class)->dispose (object);
+}
+
+static void
+nm_device_item_class_init (NMDeviceItemClass *klass)
+{
+    GObjectClass *object_class = G_OBJECT_CLASS (klass);
+    NMListItemClass *list_class = NM_LIST_ITEM_CLASS (klass);
+
+    g_type_class_add_private (object_class, sizeof (NMDeviceItemPrivate));
+
+    object_class->set_property = set_property;
+    object_class->get_property = get_property;
+    object_class->dispose = dispose;
+
+    list_class->connect = connect;
+    list_class->disconnect = disconnect;
+
+    /* Properties */
+    g_object_class_install_property
+        (object_class, PROP_DEVICE,
+         g_param_spec_object (NM_DEVICE_ITEM_DEVICE,
+                              "Device",
+                              "Device",
+                              NM_TYPE_DEVICE,
+                              G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+}
diff --git a/libnm-gtk/nm-device-item.h b/libnm-gtk/nm-device-item.h
new file mode 100644
index 0000000..be94b94
--- /dev/null
+++ b/libnm-gtk/nm-device-item.h
@@ -0,0 +1,55 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2009 Novell, Inc.
+ */
+
+#ifndef NM_DEVICE_ITEM_H
+#define NM_DEVICE_ITEM_H
+
+#include <glib-object.h>
+#include <nm-device.h>
+#include <nm-connection-item.h>
+
+G_BEGIN_DECLS
+
+#define NM_TYPE_DEVICE_ITEM            (nm_device_item_get_type ())
+#define NM_DEVICE_ITEM(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DEVICE_ITEM, NMDeviceItem))
+#define NM_DEVICE_ITEM_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_DEVICE_ITEM, NMDeviceItemClass))
+#define NM_IS_DEVICE_ITEM(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_DEVICE_ITEM))
+#define NM_IS_DEVICE_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NM_TYPE_DEVICE_ITEM))
+#define NM_DEVICE_ITEM_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DEVICE_ITEM, NMDeviceItemClass))
+
+#define NM_DEVICE_ITEM_DEVICE "device"
+
+typedef struct {
+    NMConnectionItem parent;
+} NMDeviceItem;
+
+typedef struct {
+    NMConnectionItemClass parent_class;
+
+    /* Methods */
+    char *(*get_specific_object) (NMDeviceItem *self);
+} NMDeviceItemClass;
+
+GType nm_device_item_get_type (void);
+
+NMDevice *nm_device_item_get_device (NMDeviceItem *self);
+
+G_END_DECLS
+
+#endif /* NM_DEVICE_ITEM_H */
diff --git a/libnm-gtk/nm-device-model.c b/libnm-gtk/nm-device-model.c
new file mode 100644
index 0000000..359e0ba
--- /dev/null
+++ b/libnm-gtk/nm-device-model.c
@@ -0,0 +1,266 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2009 Novell, Inc.
+ */
+
+#include <nm-device.h>
+#include <nm-device-ethernet.h>
+#include <nm-device-wifi.h>
+#include <nm-serial-device.h>
+
+#include "nm-device-model.h"
+#include "nm-icon-cache.h"
+#include "utils.h"
+
+G_DEFINE_TYPE (NMDeviceModel, nm_device_model, GTK_TYPE_LIST_STORE)
+
+enum {
+    PROP_0,
+    PROP_CLIENT,
+
+    LAST_PROP
+};
+
+#define GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), NM_TYPE_DEVICE_MODEL, NMDeviceModelPrivate))
+
+typedef struct {
+    NMClient *client;
+    gulong device_added_id;
+    gulong device_removed_id;
+
+    gboolean disposed;
+} NMDeviceModelPrivate;
+
+static GQuark quark_device_iter = 0;
+
+NMDeviceModel *
+nm_device_model_new (NMClient *client)
+{
+    g_return_val_if_fail (NM_IS_CLIENT (client), NULL);
+
+    return (NMDeviceModel *) g_object_new (NM_TYPE_DEVICE_MODEL,
+                                           NM_DEVICE_MODEL_CLIENT, client,
+                                           NULL);
+}
+
+static void
+device_state_changed (NMDevice *device,
+                      NMDeviceState new_state,
+                      NMDeviceState old_state,
+                      NMDeviceStateReason reason,
+                      gpointer user_data)
+{
+    GtkListStore *store = GTK_LIST_STORE (user_data);
+    GtkTreeIter *iter;
+
+    iter = (GtkTreeIter *) g_object_get_qdata (G_OBJECT (device), quark_device_iter);
+    if (iter)
+        gtk_list_store_set (store, iter, NM_DEVICE_MODEL_COL_STATE, new_state, -1);
+}
+
+static void
+device_added (NMClient *client,
+              NMDevice *device,
+              gpointer user_data)
+{
+    GtkListStore *store = GTK_LIST_STORE (user_data);
+    GtkTreeIter *iter;
+    GdkPixbuf *pixbuf;
+
+    iter = g_slice_new0 (GtkTreeIter);
+
+    if (NM_IS_DEVICE_ETHERNET (device))
+        pixbuf = nm_icon_cache_get ("nm-device-wired");
+    else if (NM_IS_DEVICE_WIFI (device))
+        pixbuf = nm_icon_cache_get ("nm-device-wireless");
+    else if (NM_IS_SERIAL_DEVICE (device))
+        pixbuf = nm_icon_cache_get ("nm-device-wwan");
+    else {
+        g_warning ("Unhandled device type (%s)", G_OBJECT_TYPE_NAME (device));
+        pixbuf = NULL;
+    }
+
+    gtk_list_store_append (store, iter);
+    gtk_list_store_set (store, iter,
+                        NM_DEVICE_MODEL_COL_DEVICE,        device,
+                        NM_DEVICE_MODEL_COL_IFACE,         nm_device_get_iface (device),
+                        NM_DEVICE_MODEL_COL_DESCRIPTION,   utils_get_device_description (device),
+                        NM_DEVICE_MODEL_COL_ICON,          pixbuf,
+                        NM_DEVICE_MODEL_COL_STATE,         nm_device_get_state (device),
+                        -1);
+
+    g_object_set_qdata_full (G_OBJECT (device), quark_device_iter, iter, (GDestroyNotify) gtk_tree_iter_free);
+    g_signal_connect (device, "state-changed", G_CALLBACK (device_state_changed), user_data);
+}
+
+static void
+device_removed (NMClient *client,
+                NMDevice *device,
+                gpointer user_data)
+{
+    GtkListStore *store = GTK_LIST_STORE (user_data);
+    GtkTreeIter *iter;
+
+    iter = (GtkTreeIter *) g_object_get_qdata (G_OBJECT (device), quark_device_iter);
+    if (iter) {
+        g_signal_handlers_disconnect_by_func (device, device_state_changed, user_data);
+        gtk_list_store_remove (store, iter);
+        g_object_set_qdata (G_OBJECT (device), quark_device_iter, NULL);
+    }
+}
+
+#if 0
+static int
+sort_callback (GtkTreeModel *model,
+               GtkTreeIter *a,
+               GtkTreeIter *b,
+               gpointer user_data)
+{
+    GValue value_a = {0, };
+    GValue value_b = {0, };
+    int result;
+
+    gtk_tree_model_get_value (model, a, NM_DEVICE_MODEL_COL_ITEM, &value_a);
+    gtk_tree_model_get_value (model, b, NM_DEVICE_MODEL_COL_ITEM, &value_b);
+
+    result = nm_device_item_compare (NM_DEVICE_ITEM (g_value_get_object (&value_a)),
+                                   NM_DEVICE_ITEM (g_value_get_object (&value_b)));
+
+    g_value_unset (&value_a);
+    g_value_unset (&value_b);
+
+    return result;
+}
+#endif
+
+/*****************************************************************************/
+
+static void
+nm_device_model_init (NMDeviceModel *self)
+{
+    GType types[NM_DEVICE_MODEL_N_COLUMNS];
+
+    types[NM_DEVICE_MODEL_COL_DEVICE]      = NM_TYPE_DEVICE;
+    types[NM_DEVICE_MODEL_COL_IFACE]       = G_TYPE_STRING;
+    types[NM_DEVICE_MODEL_COL_DESCRIPTION] = G_TYPE_STRING;
+    types[NM_DEVICE_MODEL_COL_ICON]        = GDK_TYPE_PIXBUF;
+    types[NM_DEVICE_MODEL_COL_STATE]       = G_TYPE_INT;
+
+    gtk_list_store_set_column_types (GTK_LIST_STORE (self), NM_DEVICE_MODEL_N_COLUMNS, types);
+#if 0
+    gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (self),
+                                     NM_DEVICE_MODEL_COL_ITEM,
+                                     sort_callback,
+                                     NULL,
+                                     NULL);
+
+    gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (self), NM_DEVICE_MODEL_COL_DEVICE, GTK_SORT_ASCENDING);
+#endif
+}
+
+static void
+set_property (GObject *object, guint prop_id,
+              const GValue *value, GParamSpec *pspec)
+{
+    NMDeviceModelPrivate *priv = GET_PRIVATE (object);
+
+    switch (prop_id) {
+    case PROP_CLIENT:
+        /* Construct only */
+        priv->client = 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)
+{
+    NMDeviceModelPrivate *priv = GET_PRIVATE (object);
+
+    switch (prop_id) {
+    case PROP_CLIENT:
+        g_value_set_object (value, priv->client);
+        break;
+    default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+        break;
+    }
+}
+
+static void
+constructed (GObject *object)
+{
+    NMDeviceModelPrivate *priv = GET_PRIVATE (object);
+    const GPtrArray *devices;
+    int i;
+
+    if (G_OBJECT_CLASS (nm_device_model_parent_class)->constructed)
+        G_OBJECT_CLASS (nm_device_model_parent_class)->constructed (object);
+
+    priv->device_added_id = g_signal_connect (priv->client, "device-added", G_CALLBACK (device_added), object);
+    priv->device_removed_id = g_signal_connect (priv->client, "device-removed", G_CALLBACK (device_removed), object);
+
+    devices = nm_client_get_devices (priv->client);
+    for (i = 0; devices && devices->len > i; i++)
+        device_added (priv->client, NM_DEVICE (g_ptr_array_index (devices, i)), object);
+}
+
+static void
+dispose (GObject *object)
+{
+    NMDeviceModelPrivate *priv = GET_PRIVATE (object);
+
+    if (!priv->disposed) {
+        g_signal_handler_disconnect (priv->client, priv->device_added_id);
+        g_signal_handler_disconnect (priv->client, priv->device_removed_id);
+
+        if (priv->client)
+            g_object_unref (priv->client);
+
+        priv->disposed = TRUE;
+    }
+
+    G_OBJECT_CLASS (nm_device_model_parent_class)->dispose (object);
+}
+
+static void
+nm_device_model_class_init (NMDeviceModelClass *klass)
+{
+    GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+    quark_device_iter = g_quark_from_static_string ("NMDeviceModel-device-iter");
+
+    g_type_class_add_private (object_class, sizeof (NMDeviceModelPrivate));
+
+    object_class->set_property = set_property;
+    object_class->get_property = get_property;
+    object_class->constructed = constructed;
+    object_class->dispose = dispose;
+
+    /* Properties */
+    g_object_class_install_property
+        (object_class, PROP_CLIENT,
+         g_param_spec_object (NM_DEVICE_MODEL_CLIENT,
+                              "NMClient",
+                              "NMClient",
+                              NM_TYPE_CLIENT,
+                              G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+}
diff --git a/libnm-gtk/nm-device-model.h b/libnm-gtk/nm-device-model.h
new file mode 100644
index 0000000..e7ff8f6
--- /dev/null
+++ b/libnm-gtk/nm-device-model.h
@@ -0,0 +1,61 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2009 Novell, Inc.
+ */
+
+#ifndef NM_DEVICE_MODEL_H
+#define NM_DEVICE_MODEL_H
+
+#include <gtk/gtk.h>
+#include <nm-client.h>
+
+G_BEGIN_DECLS
+
+#define NM_TYPE_DEVICE_MODEL            (nm_device_model_get_type ())
+#define NM_DEVICE_MODEL(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DEVICE_MODEL, NMDeviceModel))
+#define NM_DEVICE_MODEL_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_DEVICE_MODEL, NMDeviceModelClass))
+#define NM_IS_DEVICE_MODEL(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_DEVICE_MODEL))
+#define NM_IS_DEVICE_MODEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NM_TYPE_DEVICE_MODEL))
+#define NM_DEVICE_MODEL_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DEVICE_MODEL, NMDeviceModelClass))
+
+#define NM_DEVICE_MODEL_CLIENT "client"
+
+enum {
+    NM_DEVICE_MODEL_COL_DEVICE,
+    NM_DEVICE_MODEL_COL_IFACE,
+    NM_DEVICE_MODEL_COL_DESCRIPTION,
+    NM_DEVICE_MODEL_COL_ICON,
+    NM_DEVICE_MODEL_COL_STATE,
+
+    NM_DEVICE_MODEL_N_COLUMNS
+};
+
+typedef struct {
+    GtkListStore parent;
+} NMDeviceModel;
+
+typedef struct {
+    GtkListStoreClass parent_class;
+} NMDeviceModelClass;
+
+GType nm_device_model_get_type (void);
+
+NMDeviceModel *nm_device_model_new (NMClient *client);
+
+G_END_DECLS
+
+#endif /* NM_DEVICE_MODEL_H */
diff --git a/libnm-gtk/nm-device-provider.c b/libnm-gtk/nm-device-provider.c
new file mode 100644
index 0000000..54eb31e
--- /dev/null
+++ b/libnm-gtk/nm-device-provider.c
@@ -0,0 +1,154 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2009 Novell, Inc.
+ */
+
+#include "nm-device-provider.h"
+
+G_DEFINE_ABSTRACT_TYPE (NMDeviceProvider, nm_device_provider, NM_TYPE_ITEM_PROVIDER)
+
+enum {
+    PROP_0,
+    PROP_DEVICE,
+
+    LAST_PROP
+};
+
+#define GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), NM_TYPE_DEVICE_PROVIDER, NMDeviceProviderPrivate))
+
+typedef struct {
+    NMDevice *device;
+    gulong state_changed_id;
+
+    gboolean disposed;
+} NMDeviceProviderPrivate;
+
+NMDevice *
+nm_device_provider_get_device (NMDeviceProvider *self)
+{
+    g_return_val_if_fail (NM_IS_DEVICE_PROVIDER (self), NULL);
+
+    return GET_PRIVATE (self)->device;
+}
+
+gboolean
+nm_device_provider_ready (NMDeviceProvider *self)
+{
+    g_return_val_if_fail (NM_IS_DEVICE_PROVIDER (self), FALSE);
+
+    return nm_device_get_state (nm_device_provider_get_device (self)) >= NM_DEVICE_STATE_DISCONNECTED;
+}
+
+static void
+device_state_changed (NMDevice *device,
+                      NMDeviceState new_state,
+                      NMDeviceState old_state,
+                      NMDeviceStateReason reason,
+                      gpointer user_data)
+{
+    NMDeviceProvider *self = NM_DEVICE_PROVIDER (user_data);
+
+    g_debug ("device state %s changed (%d)", nm_device_get_iface (device), new_state);
+
+    if (old_state < NM_DEVICE_STATE_DISCONNECTED && new_state >= NM_DEVICE_STATE_DISCONNECTED)
+        /* Device became usable */
+        nm_item_provider_reset (NM_ITEM_PROVIDER (self));
+    else if (old_state >= NM_DEVICE_STATE_DISCONNECTED && new_state < NM_DEVICE_STATE_DISCONNECTED)
+        /* Device became unusable */
+        nm_item_provider_clear (NM_ITEM_PROVIDER (self));
+
+    if (NM_DEVICE_PROVIDER_GET_CLASS (self)->state_changed)
+        NM_DEVICE_PROVIDER_GET_CLASS (self)->state_changed (self, new_state, old_state, reason);
+}
+
+/*****************************************************************************/
+
+static void
+nm_device_provider_init (NMDeviceProvider *self)
+{
+}
+
+static void
+set_property (GObject *object, guint prop_id,
+              const GValue *value, GParamSpec *pspec)
+{
+    NMDeviceProviderPrivate *priv = GET_PRIVATE (object);
+
+    switch (prop_id) {
+    case PROP_DEVICE:
+        /* Construct only */
+        priv->device = g_value_dup_object (value);
+        priv->state_changed_id = g_signal_connect (priv->device, "state-changed",
+                                                   G_CALLBACK (device_state_changed), object);
+        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)
+{
+    NMDeviceProviderPrivate *priv = GET_PRIVATE (object);
+
+    switch (prop_id) {
+    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)
+{
+    NMDeviceProviderPrivate *priv = GET_PRIVATE (object);
+
+    if (!priv->disposed) {
+        g_signal_handler_disconnect (priv->device, priv->state_changed_id);
+        g_object_unref (priv->device);
+
+        priv->disposed = TRUE;
+    }
+
+    G_OBJECT_CLASS (nm_device_provider_parent_class)->dispose (object);
+}
+
+static void
+nm_device_provider_class_init (NMDeviceProviderClass *klass)
+{
+    GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+    g_type_class_add_private (object_class, sizeof (NMDeviceProviderPrivate));
+
+    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_DEVICE,
+         g_param_spec_object (NM_DEVICE_PROVIDER_DEVICE,
+                              "NMDevice",
+                              "NMDevice",
+                              NM_TYPE_DEVICE,
+                              G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+}
diff --git a/libnm-gtk/nm-device-provider.h b/libnm-gtk/nm-device-provider.h
new file mode 100644
index 0000000..70695d7
--- /dev/null
+++ b/libnm-gtk/nm-device-provider.h
@@ -0,0 +1,59 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2009 Novell, Inc.
+ */
+
+#ifndef NM_DEVICE_PROVIDER_H
+#define NM_DEVICE_PROVIDER_H
+
+#include <glib-object.h>
+#include <nm-device.h>
+#include <nm-item-provider.h>
+
+G_BEGIN_DECLS
+
+#define NM_TYPE_DEVICE_PROVIDER            (nm_device_provider_get_type ())
+#define NM_DEVICE_PROVIDER(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DEVICE_PROVIDER, NMDeviceProvider))
+#define NM_DEVICE_PROVIDER_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_DEVICE_PROVIDER, NMDeviceProviderClass))
+#define NM_IS_DEVICE_PROVIDER(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_DEVICE_PROVIDER))
+#define NM_IS_DEVICE_PROVIDER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NM_TYPE_DEVICE_PROVIDER))
+#define NM_DEVICE_PROVIDER_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DEVICE_PROVIDER, NMDeviceProviderClass))
+
+#define NM_DEVICE_PROVIDER_DEVICE "device"
+
+typedef struct {
+    NMItemProvider parent;
+} NMDeviceProvider;
+
+typedef struct {
+    NMItemProviderClass parent_class;
+
+    /* Methods */
+    void (*state_changed) (NMDeviceProvider *self,
+                           NMDeviceState new_state,
+                           NMDeviceState old_state,
+                           NMDeviceStateReason reason);
+} NMDeviceProviderClass;
+
+GType nm_device_provider_get_type (void);
+
+NMDevice *nm_device_provider_get_device (NMDeviceProvider *self);
+gboolean  nm_device_provider_ready      (NMDeviceProvider *self);
+
+G_END_DECLS
+
+#endif /* NM_DEVICE_PROVIDER_H */
diff --git a/libnm-gtk/nm-ethernet-item.c b/libnm-gtk/nm-ethernet-item.c
new file mode 100644
index 0000000..1e9a277
--- /dev/null
+++ b/libnm-gtk/nm-ethernet-item.c
@@ -0,0 +1,116 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2009 Novell, Inc.
+ */
+
+#include <string.h>
+#include <glib/gi18n.h>
+#include <nm-setting-8021x.h>
+#include "nm-ethernet-item.h"
+#include "nm-icon-cache.h"
+
+G_DEFINE_TYPE (NMEthernetItem, nm_ethernet_item, NM_TYPE_DEVICE_ITEM)
+
+NMListItem *
+nm_ethernet_item_new (NMClient *client,
+                      NMDeviceEthernet *device,
+                      NMSettingsConnectionInterface *connection)
+{
+    g_return_val_if_fail (NM_IS_CLIENT (client), NULL);
+    g_return_val_if_fail (NM_IS_DEVICE_ETHERNET (device), NULL);
+    g_return_val_if_fail (NM_IS_SETTINGS_CONNECTION_INTERFACE (connection), NULL);
+
+    return (NMListItem *) g_object_new (NM_TYPE_ETHERNET_ITEM,
+                                        NM_LIST_ITEM_TYPE_NAME, _("wired"),
+                                        NM_CONNECTION_ITEM_CLIENT, client,
+                                        NM_CONNECTION_ITEM_CONNECTION, connection,
+                                        NM_DEVICE_ITEM_DEVICE, device,
+                                        NULL);
+}
+
+static void
+update_icon (NMEthernetItem *self)
+{
+    const char *icon;
+    NMListItemStatus status;
+
+    status = nm_list_item_get_status (NM_LIST_ITEM (self));
+    if (status == NM_LIST_ITEM_STATUS_CONNECTED)
+        icon = "nm-device-wired";
+    else
+        icon = "nm-no-connection";
+
+    if (icon)
+        g_object_set (self, NM_LIST_ITEM_ICON, icon, NULL);
+}
+
+static int
+priority (NMListItem *item)
+{
+    return NM_LIST_ITEM_PRIORITY_DEV_ETHERNET + NM_LIST_ITEM_CLASS (nm_ethernet_item_parent_class)->priority (item);
+}
+
+/*****************************************************************************/
+
+static void
+nm_ethernet_item_init (NMEthernetItem *self)
+{
+    update_icon (self);
+}
+
+static void
+constructed (GObject *object)
+{
+    NMConnection *connection;
+    NMSetting *setting;
+
+    if (G_OBJECT_CLASS (nm_ethernet_item_parent_class)->constructed)
+        G_OBJECT_CLASS (nm_ethernet_item_parent_class)->constructed (object);
+
+    connection = NM_CONNECTION (nm_connection_item_get_connection (NM_CONNECTION_ITEM (object)));
+    setting = nm_connection_get_setting (connection, NM_TYPE_SETTING_802_1X);
+
+    if (setting)
+        g_object_set (object, NM_LIST_ITEM_SECURITY, _("802.1x"), NULL);
+}
+
+static void
+notify (GObject *object,
+        GParamSpec *pspec)
+{
+    if (!pspec || !pspec->name)
+        return;
+
+    if (!strcmp (pspec->name, NM_LIST_ITEM_STATUS))
+        update_icon (NM_ETHERNET_ITEM (object));
+    else if (!strcmp (pspec->name, NM_CONNECTION_ITEM_CONNECTION) && 
+             !nm_connection_item_get_connection (NM_CONNECTION_ITEM (object)))
+        /* If the connection is removed from the item, request deletion */
+        nm_list_item_request_remove (NM_LIST_ITEM (object));
+}
+
+static void
+nm_ethernet_item_class_init (NMEthernetItemClass *klass)
+{
+    GObjectClass *object_class = G_OBJECT_CLASS (klass);
+    NMListItemClass *list_class = NM_LIST_ITEM_CLASS (klass);
+
+    object_class->constructed = constructed;
+    object_class->notify = notify;
+
+    list_class->priority = priority;
+}
diff --git a/libnm-gtk/nm-ethernet-item.h b/libnm-gtk/nm-ethernet-item.h
new file mode 100644
index 0000000..9662742
--- /dev/null
+++ b/libnm-gtk/nm-ethernet-item.h
@@ -0,0 +1,52 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2009 Novell, Inc.
+ */
+
+#ifndef NM_ETHERNET_ITEM_H
+#define NM_ETHERNET_ITEM_H
+
+#include <glib-object.h>
+#include <nm-device-ethernet.h>
+#include <nm-device-item.h>
+
+G_BEGIN_DECLS
+
+#define NM_TYPE_ETHERNET_ITEM            (nm_ethernet_item_get_type ())
+#define NM_ETHERNET_ITEM(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_ETHERNET_ITEM, NMEthernetItem))
+#define NM_ETHERNET_ITEM_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_ETHERNET_ITEM, NMEthernetItemClass))
+#define NM_IS_ETHERNET_ITEM(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_ETHERNET_ITEM))
+#define NM_IS_ETHERNET_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NM_TYPE_ETHERNET_ITEM))
+#define NM_ETHERNET_ITEM_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_ETHERNET_ITEM, NMEthernetItemClass))
+
+typedef struct {
+    NMDeviceItem parent;
+} NMEthernetItem;
+
+typedef struct {
+    NMDeviceItemClass parent_class;
+} NMEthernetItemClass;
+
+GType nm_ethernet_item_get_type (void);
+
+NMListItem *nm_ethernet_item_new (NMClient *client,
+                                  NMDeviceEthernet *device,
+                                  NMSettingsConnectionInterface *connection);
+
+G_END_DECLS
+
+#endif /* NM_ETHERNET_ITEM_H */
diff --git a/libnm-gtk/nm-ethernet-provider.c b/libnm-gtk/nm-ethernet-provider.c
new file mode 100644
index 0000000..6305edc
--- /dev/null
+++ b/libnm-gtk/nm-ethernet-provider.c
@@ -0,0 +1,71 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2009 Novell, Inc.
+ */
+
+#include "nm-ethernet-provider.h"
+#include "nm-ethernet-item.h"
+#include "utils.h"
+
+G_DEFINE_TYPE (NMEthernetProvider, nm_ethernet_provider, NM_TYPE_DEVICE_PROVIDER)
+
+NMItemProvider *
+nm_ethernet_provider_new (NMClient *client,
+                          NMDeviceEthernet *device)
+{
+    g_return_val_if_fail (NM_IS_CLIENT (client), NULL);
+    g_return_val_if_fail (NM_IS_DEVICE_ETHERNET (device), NULL);
+
+    return (NMItemProvider *) g_object_new (NM_TYPE_ETHERNET_PROVIDER,
+                                            NM_ITEM_PROVIDER_CLIENT, client,
+                                            NM_DEVICE_PROVIDER_DEVICE, device,
+                                            NULL);
+}
+
+static void
+ethernet_added (NMItemProvider *provider,
+                NMSettingsConnectionInterface *connection)
+{
+    NMDeviceProvider *device_provider = NM_DEVICE_PROVIDER (provider);
+    NMDevice *device;
+
+    if (!nm_device_provider_ready (device_provider))
+        return;
+
+    device = nm_device_provider_get_device (device_provider);
+    if (utils_connection_valid_for_device (NM_CONNECTION (connection), device, NULL)) {
+        NMListItem *item;
+
+        item = nm_ethernet_item_new (nm_item_provider_get_client (provider), NM_DEVICE_ETHERNET (device), connection);
+        nm_item_provider_item_added (provider, item);
+    }
+}
+
+/*****************************************************************************/
+
+static void
+nm_ethernet_provider_init (NMEthernetProvider *self)
+{
+}
+
+static void
+nm_ethernet_provider_class_init (NMEthernetProviderClass *klass)
+{
+    NMItemProviderClass *item_class = NM_ITEM_PROVIDER_CLASS (klass);
+
+    item_class->connection_added = ethernet_added;
+}
diff --git a/libnm-gtk/nm-ethernet-provider.h b/libnm-gtk/nm-ethernet-provider.h
new file mode 100644
index 0000000..20f8c95
--- /dev/null
+++ b/libnm-gtk/nm-ethernet-provider.h
@@ -0,0 +1,51 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2009 Novell, Inc.
+ */
+
+#ifndef NM_ETHERNET_PROVIDER_H
+#define NM_ETHERNET_PROVIDER_H
+
+#include <glib-object.h>
+#include <nm-device-ethernet.h>
+#include <nm-device-provider.h>
+
+G_BEGIN_DECLS
+
+#define NM_TYPE_ETHERNET_PROVIDER            (nm_ethernet_provider_get_type ())
+#define NM_ETHERNET_PROVIDER(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_ETHERNET_PROVIDER, NMEthernetProvider))
+#define NM_ETHERNET_PROVIDER_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_ETHERNET_PROVIDER, NMEthernetProviderClass))
+#define NM_IS_ETHERNET_PROVIDER(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_ETHERNET_PROVIDER))
+#define NM_IS_ETHERNET_PROVIDER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NM_TYPE_ETHERNET_PROVIDER))
+#define NM_ETHERNET_PROVIDER_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_ETHERNET_PROVIDER, NMEthernetProviderClass))
+
+typedef struct {
+    NMDeviceProvider parent;
+} NMEthernetProvider;
+
+typedef struct {
+    NMDeviceProviderClass parent_class;
+} NMEthernetProviderClass;
+
+GType nm_ethernet_provider_get_type (void);
+
+NMItemProvider *nm_ethernet_provider_new (NMClient *client,
+                                          NMDeviceEthernet *device);
+
+G_END_DECLS
+
+#endif /* NM_ETHERNET_PROVIDER_H */
diff --git a/src/gconf-helpers/nma-gconf-connection.c b/libnm-gtk/nm-gconf-connection.c
similarity index 86%
rename from src/gconf-helpers/nma-gconf-connection.c
rename to libnm-gtk/nm-gconf-connection.c
index 51fe667..0117e84 100644
--- a/src/gconf-helpers/nma-gconf-connection.c
+++ b/libnm-gtk/nm-gconf-connection.c
@@ -31,7 +31,7 @@
 #include <nm-setting-vpn.h>
 #include <nm-setting-8021x.h>
 
-#include "nma-gconf-connection.h"
+#include "nm-gconf-connection.h"
 #include "gconf-helpers.h"
 #include "nm-utils.h"
 #include "utils.h"
@@ -42,18 +42,18 @@ static NMSettingsConnectionInterface *parent_settings_connection_iface;
 
 static void settings_connection_interface_init (NMSettingsConnectionInterface *class);
 
-G_DEFINE_TYPE_EXTENDED (NMAGConfConnection, nma_gconf_connection, NM_TYPE_EXPORTED_CONNECTION, 0,
+G_DEFINE_TYPE_EXTENDED (NMGConfConnection, nm_gconf_connection, NM_TYPE_EXPORTED_CONNECTION, 0,
                         G_IMPLEMENT_INTERFACE (NM_TYPE_SETTINGS_CONNECTION_INTERFACE,
                                                settings_connection_interface_init))
 
-#define NMA_GCONF_CONNECTION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NMA_TYPE_GCONF_CONNECTION, NMAGConfConnectionPrivate))
+#define NM_GCONF_CONNECTION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_GCONF_CONNECTION, NMGConfConnectionPrivate))
 
 typedef struct {
 	GConfClient *client;
 	char *dir;
 
 	gboolean disposed;
-} NMAGConfConnectionPrivate;
+} NMGConfConnectionPrivate;
 
 enum {
 	PROP_0,
@@ -71,11 +71,11 @@ enum {
 
 static guint signals[LAST_SIGNAL] = { 0 };
 
-NMAGConfConnection *
-nma_gconf_connection_new (GConfClient *client, const char *conf_dir)
+NMGConfConnection *
+nm_gconf_connection_new (GConfClient *client, const char *conf_dir)
 {
 	NMConnection *connection;
-	NMAGConfConnection *gconf_connection;
+	NMGConfConnection *gconf_connection;
 
 	g_return_val_if_fail (GCONF_IS_CLIENT (client), NULL);
 	g_return_val_if_fail (conf_dir != NULL, NULL);
@@ -83,7 +83,7 @@ nma_gconf_connection_new (GConfClient *client, const char *conf_dir)
 	/* retrieve GConf data */
 	connection = nm_gconf_read_connection (client, conf_dir);
 	if (connection) {
-		gconf_connection = nma_gconf_connection_new_from_connection (client, conf_dir, connection);
+		gconf_connection = nm_gconf_connection_new_from_connection (client, conf_dir, connection);
 		g_object_unref (connection);
 	} else {
 		nm_warning ("No connection read from GConf at %s.", conf_dir);
@@ -93,13 +93,13 @@ nma_gconf_connection_new (GConfClient *client, const char *conf_dir)
 	return gconf_connection;
 }
 
-NMAGConfConnection *
-nma_gconf_connection_new_from_connection (GConfClient *client,
-                                          const char *conf_dir,
-                                          NMConnection *connection)
+NMGConfConnection *
+nm_gconf_connection_new_from_connection (GConfClient *client,
+										 const char *conf_dir,
+										 NMConnection *connection)
 {
 	GObject *object;
-	NMAGConfConnection *self;
+	NMGConfConnection *self;
 	GError *error = NULL;
 	gboolean success;
 	GHashTable *settings;
@@ -120,15 +120,15 @@ nma_gconf_connection_new_from_connection (GConfClient *client,
 		return NULL;
 	}
 
-	object = g_object_new (NMA_TYPE_GCONF_CONNECTION,
-	                       NMA_GCONF_CONNECTION_CLIENT, client,
-	                       NMA_GCONF_CONNECTION_DIR, conf_dir,
+	object = g_object_new (NM_TYPE_GCONF_CONNECTION,
+	                       NM_GCONF_CONNECTION_CLIENT, client,
+	                       NM_GCONF_CONNECTION_DIR, conf_dir,
 	                       NM_CONNECTION_SCOPE, NM_CONNECTION_SCOPE_USER,
 	                       NULL);
 	if (!object)
 		return NULL;
 
-	self = NMA_GCONF_CONNECTION (object);
+	self = NM_GCONF_CONNECTION (object);
 
 	/* Fill certs so that the nm_connection_replace_settings verification works */
 	settings = nm_connection_to_hash (connection);
@@ -142,17 +142,17 @@ nma_gconf_connection_new_from_connection (GConfClient *client,
 }
 
 const char *
-nma_gconf_connection_get_gconf_path (NMAGConfConnection *self)
+nm_gconf_connection_get_gconf_path (NMGConfConnection *self)
 {
-	g_return_val_if_fail (NMA_IS_GCONF_CONNECTION (self), NULL);
+	g_return_val_if_fail (NM_IS_GCONF_CONNECTION (self), NULL);
 
-	return NMA_GCONF_CONNECTION_GET_PRIVATE (self)->dir;
+	return NM_GCONF_CONNECTION_GET_PRIVATE (self)->dir;
 }
 
 gboolean
-nma_gconf_connection_gconf_changed (NMAGConfConnection *self)
+nm_gconf_connection_gconf_changed (NMGConfConnection *self)
 {
-	NMAGConfConnectionPrivate *priv = NMA_GCONF_CONNECTION_GET_PRIVATE (self);
+	NMGConfConnectionPrivate *priv = NM_GCONF_CONNECTION_GET_PRIVATE (self);
 	NMConnection *new;
 	GHashTable *new_settings;
 	GError *error = NULL;
@@ -197,7 +197,7 @@ nma_gconf_connection_gconf_changed (NMAGConfConnection *self)
 	nm_settings_connection_interface_emit_updated (NM_SETTINGS_CONNECTION_INTERFACE (self));
 	return TRUE;
 
-invalid:
+ invalid:
 	g_clear_error (&error);
 	g_signal_emit_by_name (self, NM_SETTINGS_CONNECTION_INTERFACE_REMOVED);
 	return FALSE;
@@ -246,11 +246,11 @@ destroy_gvalue (gpointer data)
 }
 
 static GHashTable *
-nma_gconf_connection_get_keyring_items (NMAGConfConnection *self,
-                                        const char *setting_name,
-                                        GError **error)
+nm_gconf_connection_get_keyring_items (NMGConfConnection *self,
+									   const char *setting_name,
+									   GError **error)
 {
-	NMAGConfConnectionPrivate *priv;
+	NMGConfConnectionPrivate *priv;
 	NMSettingConnection *s_con;
 	GHashTable *secrets;
 	GList *found_list = NULL;
@@ -264,7 +264,7 @@ nma_gconf_connection_get_keyring_items (NMAGConfConnection *self,
 	g_return_val_if_fail (error != NULL, NULL);
 	g_return_val_if_fail (*error == NULL, NULL);
 
-	priv = NMA_GCONF_CONNECTION_GET_PRIVATE (self);
+	priv = NM_GCONF_CONNECTION_GET_PRIVATE (self);
 
 	s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (NM_CONNECTION (self), NM_TYPE_SETTING_CONNECTION));
 	g_assert (s_con);
@@ -298,7 +298,7 @@ nma_gconf_connection_get_keyring_items (NMAGConfConnection *self,
 
 			attr = &(gnome_keyring_attribute_list_index (found->attributes, i));
 			if (   (strcmp (attr->name, KEYRING_SK_TAG) == 0)
-			    && (attr->type == GNOME_KEYRING_ATTRIBUTE_TYPE_STRING)) {
+				   && (attr->type == GNOME_KEYRING_ATTRIBUTE_TYPE_STRING)) {
 				key_name = attr->value.string;
 				break;
 			}
@@ -368,7 +368,7 @@ delete_done (GnomeKeyringResult result, gpointer user_data)
 }
 
 static void
-clear_keyring_items (NMAGConfConnection *self)
+clear_keyring_items (NMGConfConnection *self)
 {
 	NMSettingConnection *s_con;
 	const char *uuid;
@@ -413,7 +413,7 @@ update (NMSettingsConnectionInterface *connection,
 	    NMSettingsConnectionInterfaceUpdateFunc callback,
 	    gpointer user_data)
 {
-	NMAGConfConnectionPrivate *priv = NMA_GCONF_CONNECTION_GET_PRIVATE (connection);
+	NMGConfConnectionPrivate *priv = NM_GCONF_CONNECTION_GET_PRIVATE (connection);
 
 	nm_gconf_write_connection (NM_CONNECTION (connection),
 	                           priv->client,
@@ -429,12 +429,12 @@ do_delete (NMSettingsConnectionInterface *connection,
 	       NMSettingsConnectionInterfaceDeleteFunc callback,
 	       gpointer user_data)
 {
-	NMAGConfConnectionPrivate *priv = NMA_GCONF_CONNECTION_GET_PRIVATE (connection);
+	NMGConfConnectionPrivate *priv = NM_GCONF_CONNECTION_GET_PRIVATE (connection);
 	gboolean success;
 	GError *error = NULL;
 
 	/* Clean up keyring keys */
-	clear_keyring_items (NMA_GCONF_CONNECTION (connection));
+	clear_keyring_items (NM_GCONF_CONNECTION (connection));
 
 	success = gconf_client_recursive_unset (priv->client, priv->dir, 0, &error);
 	if (!success) {
@@ -453,11 +453,11 @@ internal_get_secrets (NMSettingsConnectionInterface *connection,
                       const char **hints,
                       gboolean request_new,
                       gboolean local,
-                      NMANewSecretsRequestedFunc callback,
+                      NMNewSecretsRequestedFunc callback,
                       gpointer callback_data,
                       GError **error)
 {
-	NMAGConfConnection *self = NMA_GCONF_CONNECTION (connection);
+	NMGConfConnection *self = NM_GCONF_CONNECTION (connection);
 	GHashTable *settings = NULL;
 	GHashTable *secrets = NULL;
 	NMSettingConnection *s_con;
@@ -493,7 +493,7 @@ internal_get_secrets (NMSettingsConnectionInterface *connection,
 
 	/* Only try to get new secrets for D-Bus requests */
 	if (local) {
-		secrets = nma_gconf_connection_get_keyring_items (self, setting_name, error);
+		secrets = nm_gconf_connection_get_keyring_items (self, setting_name, error);
 		if (!secrets && error && *error)
 			return FALSE;
 	} else {
@@ -508,7 +508,7 @@ internal_get_secrets (NMSettingsConnectionInterface *connection,
 			goto get_secrets;
 		}
 
-		secrets = nma_gconf_connection_get_keyring_items (self, setting_name, error);
+		secrets = nm_gconf_connection_get_keyring_items (self, setting_name, error);
 		if (!secrets) {
 			if (error && *error)
 				return FALSE;
@@ -521,7 +521,7 @@ internal_get_secrets (NMSettingsConnectionInterface *connection,
 		if (g_hash_table_size (secrets) == 0) {
 			g_hash_table_destroy (secrets);
 			nm_warning ("%s.%d - Secrets were found for setting '%s' but none"
-					  " were valid.", __FILE__, __LINE__, setting_name);
+						" were valid.", __FILE__, __LINE__, setting_name);
 			goto get_secrets;
 		}
 
@@ -565,7 +565,7 @@ internal_get_secrets (NMSettingsConnectionInterface *connection,
 	g_hash_table_destroy (settings);
 	return TRUE;
 
-get_secrets:
+ get_secrets:
 	g_signal_emit (self,
 	               signals[NEW_SECRETS_REQUESTED],
 	               0,
@@ -675,7 +675,7 @@ is_dbus_request_authorized (DBusGMethodInvocation *context,
 
 	/* And finally, the actual UID check */
 	if (   (allow_user && (sender_uid == geteuid()))
-	    || (sender_uid == 0))
+		   || (sender_uid == 0))
 		success = TRUE;
 	else {
 		g_set_error (error, NM_SETTINGS_INTERFACE_ERROR,
@@ -683,7 +683,7 @@ is_dbus_request_authorized (DBusGMethodInvocation *context,
 		             "%s", "Requestor UID does not match the UID of the user settings service");
 	}
 
-out:
+ out:
 	if (bus)
 		dbus_g_connection_unref (bus);
 	g_free (sender);
@@ -708,7 +708,7 @@ dbus_update (NMExportedConnection *exported,
              GHashTable *new_settings,
              DBusGMethodInvocation *context)
 {
-	NMAGConfConnection *self = NMA_GCONF_CONNECTION (exported);
+	NMGConfConnection *self = NM_GCONF_CONNECTION (exported);
 	NMConnection *new;
 	gboolean success = FALSE;
 	GError *error = NULL;
@@ -754,7 +754,7 @@ static void
 dbus_delete (NMExportedConnection *exported,
              DBusGMethodInvocation *context)
 {
-	NMAGConfConnection *self = NMA_GCONF_CONNECTION (exported);
+	NMGConfConnection *self = NM_GCONF_CONNECTION (exported);
 	GError *error = NULL;
 
 	/* Restrict Update to execution by the current user and root for DBus invocation */
@@ -832,7 +832,7 @@ dbus_get_settings (NMExportedConnection *connection, GError **error)
 		added = TRUE;
 	}
 
-	settings = NM_EXPORTED_CONNECTION_CLASS (nma_gconf_connection_parent_class)->get_settings (connection, error);
+	settings = NM_EXPORTED_CONNECTION_CLASS (nm_gconf_connection_parent_class)->get_settings (connection, error);
 
 	if (added)
 		g_object_set (s_vpn, NM_SETTING_VPN_USER_NAME, NULL, NULL);
@@ -853,7 +853,7 @@ settings_connection_interface_init (NMSettingsConnectionInterface *iface)
 }
 
 static void
-nma_gconf_connection_init (NMAGConfConnection *connection)
+nm_gconf_connection_init (NMGConfConnection *connection)
 {
 }
 
@@ -863,14 +863,14 @@ constructor (GType type,
              GObjectConstructParam *construct_params)
 {
 	GObject *object;
-	NMAGConfConnectionPrivate *priv;
+	NMGConfConnectionPrivate *priv;
 
-	object = G_OBJECT_CLASS (nma_gconf_connection_parent_class)->constructor (type, n_construct_params, construct_params);
+	object = G_OBJECT_CLASS (nm_gconf_connection_parent_class)->constructor (type, n_construct_params, construct_params);
 
 	if (!object)
 		return NULL;
 
-	priv = NMA_GCONF_CONNECTION_GET_PRIVATE (object);
+	priv = NM_GCONF_CONNECTION_GET_PRIVATE (object);
 
 	if (!priv->client) {
 		nm_warning ("GConfClient not provided.");
@@ -890,7 +890,7 @@ constructor (GType type,
 static void
 dispose (GObject *object)
 {
-	NMAGConfConnectionPrivate *priv = NMA_GCONF_CONNECTION_GET_PRIVATE (object);
+	NMGConfConnectionPrivate *priv = NM_GCONF_CONNECTION_GET_PRIVATE (object);
 
 	if (priv->disposed)
 		return;
@@ -898,24 +898,24 @@ dispose (GObject *object)
 
 	g_object_unref (priv->client);
 
-	G_OBJECT_CLASS (nma_gconf_connection_parent_class)->dispose (object);
+	G_OBJECT_CLASS (nm_gconf_connection_parent_class)->dispose (object);
 }
 
 static void
 finalize (GObject *object)
 {
-	NMAGConfConnectionPrivate *priv = NMA_GCONF_CONNECTION_GET_PRIVATE (object);
+	NMGConfConnectionPrivate *priv = NM_GCONF_CONNECTION_GET_PRIVATE (object);
 
 	g_free (priv->dir);
 
-	G_OBJECT_CLASS (nma_gconf_connection_parent_class)->finalize (object);
+	G_OBJECT_CLASS (nm_gconf_connection_parent_class)->finalize (object);
 }
 
 static void
 set_property (GObject *object, guint prop_id,
-		    const GValue *value, GParamSpec *pspec)
+			  const GValue *value, GParamSpec *pspec)
 {
-	NMAGConfConnectionPrivate *priv = NMA_GCONF_CONNECTION_GET_PRIVATE (object);
+	NMGConfConnectionPrivate *priv = NM_GCONF_CONNECTION_GET_PRIVATE (object);
 
 	switch (prop_id) {
 	case PROP_CLIENT:
@@ -934,9 +934,9 @@ set_property (GObject *object, guint prop_id,
 
 static void
 get_property (GObject *object, guint prop_id,
-		    GValue *value, GParamSpec *pspec)
+			  GValue *value, GParamSpec *pspec)
 {
-	NMAGConfConnectionPrivate *priv = NMA_GCONF_CONNECTION_GET_PRIVATE (object);
+	NMGConfConnectionPrivate *priv = NM_GCONF_CONNECTION_GET_PRIVATE (object);
 
 	switch (prop_id) {
 	case PROP_CLIENT:
@@ -952,12 +952,12 @@ get_property (GObject *object, guint prop_id,
 }
 
 static void
-nma_gconf_connection_class_init (NMAGConfConnectionClass *class)
+nm_gconf_connection_class_init (NMGConfConnectionClass *class)
 {
 	GObjectClass *object_class = G_OBJECT_CLASS (class);
 	NMExportedConnectionClass *ec_class = NM_EXPORTED_CONNECTION_CLASS (class);
 
-	g_type_class_add_private (class, sizeof (NMAGConfConnectionPrivate));
+	g_type_class_add_private (class, sizeof (NMGConfConnectionPrivate));
 
 	/* Virtual methods */
 	object_class->constructor  = constructor;
@@ -974,28 +974,28 @@ nma_gconf_connection_class_init (NMAGConfConnectionClass *class)
 	/* Properties */
 	g_object_class_install_property
 		(object_class, PROP_CLIENT,
-		 g_param_spec_object (NMA_GCONF_CONNECTION_CLIENT,
-						  "GConfClient",
-						  "GConfClient",
-						  GCONF_TYPE_CLIENT,
-						  G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+		 g_param_spec_object (NM_GCONF_CONNECTION_CLIENT,
+							  "GConfClient",
+							  "GConfClient",
+							  GCONF_TYPE_CLIENT,
+							  G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
 
 	g_object_class_install_property
 		(object_class, PROP_DIR,
-		 g_param_spec_string (NMA_GCONF_CONNECTION_DIR,
-						  "GConf directory",
-						  "GConf directory",
-						  NULL,
-						  G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+		 g_param_spec_string (NM_GCONF_CONNECTION_DIR,
+							  "GConf directory",
+							  "GConf directory",
+							  NULL,
+							  G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
 
 	/* Signals */
 	signals[NEW_SECRETS_REQUESTED] =
 		g_signal_new ("new-secrets-requested",
-				    G_OBJECT_CLASS_TYPE (object_class),
-				    G_SIGNAL_RUN_FIRST,
-				    G_STRUCT_OFFSET (NMAGConfConnectionClass, new_secrets_requested),
-				    NULL, NULL,
-				    nma_marshal_VOID__STRING_POINTER_BOOLEAN_POINTER_POINTER,
-				    G_TYPE_NONE, 5,
-				    G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_BOOLEAN, G_TYPE_POINTER, G_TYPE_POINTER);
+					  G_OBJECT_CLASS_TYPE (object_class),
+					  G_SIGNAL_RUN_FIRST,
+					  G_STRUCT_OFFSET (NMGConfConnectionClass, new_secrets_requested),
+					  NULL, NULL,
+					  nma_marshal_VOID__STRING_POINTER_BOOLEAN_POINTER_POINTER,
+					  G_TYPE_NONE, 5,
+					  G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_BOOLEAN, G_TYPE_POINTER, G_TYPE_POINTER);
 }
diff --git a/libnm-gtk/nm-gconf-connection.h b/libnm-gtk/nm-gconf-connection.h
new file mode 100644
index 0000000..00a3883
--- /dev/null
+++ b/libnm-gtk/nm-gconf-connection.h
@@ -0,0 +1,78 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* NetworkManager Wireless Applet -- Display wireless access points and allow user control
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2008 Novell, Inc.
+ * (C) Copyright 2008 Red Hat, Inc.
+ */
+
+#ifndef NM_GCONF_CONNECTION_H
+#define NM_GCONF_CONNECTION_H
+
+#include <gconf/gconf-client.h>
+#include <dbus/dbus-glib.h>
+#include <nm-connection.h>
+#include <nm-exported-connection.h>
+#include <nm-settings-connection-interface.h>
+
+G_BEGIN_DECLS
+
+#define NM_TYPE_GCONF_CONNECTION            (nm_gconf_connection_get_type ())
+#define NM_GCONF_CONNECTION(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_GCONF_CONNECTION, NMGConfConnection))
+#define NM_GCONF_CONNECTION_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_GCONF_CONNECTION, NMGConfConnectionClass))
+#define NM_IS_GCONF_CONNECTION(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_GCONF_CONNECTION))
+#define NM_IS_GCONF_CONNECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NM_TYPE_GCONF_CONNECTION))
+#define NM_GCONF_CONNECTION_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_GCONF_CONNECTION, NMGConfConnectionClass))
+
+#define NM_GCONF_CONNECTION_CLIENT "client"
+#define NM_GCONF_CONNECTION_DIR    "dir"
+
+typedef struct {
+	NMExportedConnection parent;
+} NMGConfConnection;
+
+typedef void (*NMNewSecretsRequestedFunc) (NMSettingsConnectionInterface *connection,
+										   GHashTable *settings,
+										   GError *error,
+										   gpointer user_data);
+
+typedef struct {
+	NMExportedConnectionClass parent;
+
+	/* Signals */
+	void (*new_secrets_requested)  (NMGConfConnection *self,
+	                                const char *setting_name,
+	                                const char **hints,
+	                                gboolean ask_user,
+	                                DBusGMethodInvocation *context);
+} NMGConfConnectionClass;
+
+GType nm_gconf_connection_get_type (void);
+
+NMGConfConnection *nm_gconf_connection_new  (GConfClient *client,
+											 const char *conf_dir);
+
+NMGConfConnection *nm_gconf_connection_new_from_connection (GConfClient *client,
+															const char *conf_dir,
+															NMConnection *connection);
+
+gboolean nm_gconf_connection_gconf_changed (NMGConfConnection *self);
+
+const char *nm_gconf_connection_get_gconf_path (NMGConfConnection *self);
+
+G_END_DECLS
+
+#endif /* NM_GCONF_CONNECTION_H */
diff --git a/src/gconf-helpers/nma-gconf-settings.c b/libnm-gtk/nm-gconf-settings.c
similarity index 68%
rename from src/gconf-helpers/nma-gconf-settings.c
rename to libnm-gtk/nm-gconf-settings.c
index 986d947..e9b0b21 100644
--- a/src/gconf-helpers/nma-gconf-settings.c
+++ b/libnm-gtk/nm-gconf-settings.c
@@ -21,14 +21,14 @@
 #include <string.h>
 #include <stdio.h>
 
-#include "nma-gconf-settings.h"
+#include "nm-gconf-settings.h"
 #include "gconf-helpers.h"
 #include "nma-marshal.h"
 #include "nm-utils.h"
 
-G_DEFINE_TYPE (NMAGConfSettings, nma_gconf_settings, NM_TYPE_SETTINGS_SERVICE)
+G_DEFINE_TYPE (NMGConfSettings, nm_gconf_settings, NM_TYPE_SETTINGS_SERVICE)
 
-#define NMA_GCONF_SETTINGS_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NMA_TYPE_GCONF_SETTINGS, NMAGConfSettingsPrivate))
+#define NM_GCONF_SETTINGS_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_GCONF_SETTINGS, NMGConfSettingsPrivate))
 
 typedef struct {
 	GConfClient *client;
@@ -36,9 +36,10 @@ typedef struct {
 	GSList *connections;
 	guint read_connections_id;
 	GHashTable *pending_changes;
+	gboolean reading_connections;
 
 	gboolean disposed;
-} NMAGConfSettingsPrivate;
+} NMGConfSettingsPrivate;
 
 enum {
 	NEW_SECRETS_REQUESTED,
@@ -49,25 +50,25 @@ enum {
 static guint signals[LAST_SIGNAL] = { 0 };
 
 
-NMAGConfSettings *
-nma_gconf_settings_new (DBusGConnection *bus)
+NMGConfSettings *
+nm_gconf_settings_new (DBusGConnection *bus)
 {
-	return (NMAGConfSettings *) g_object_new (NMA_TYPE_GCONF_SETTINGS,
-	                                          NM_SETTINGS_SERVICE_SCOPE, NM_CONNECTION_SCOPE_USER,
-	                                          NM_SETTINGS_SERVICE_BUS, bus,
-	                                          NULL);
+	return (NMGConfSettings *) g_object_new (NM_TYPE_GCONF_SETTINGS,
+											 NM_SETTINGS_SERVICE_SCOPE, NM_CONNECTION_SCOPE_USER,
+											 NM_SETTINGS_SERVICE_BUS, bus,
+											 NULL);
 }
 
 static void
-connection_new_secrets_requested_cb (NMAGConfConnection *connection,
+connection_new_secrets_requested_cb (NMGConfConnection *connection,
                                      const char *setting_name,
                                      const char **hints,
                                      gboolean ask_user,
-                                     NMANewSecretsRequestedFunc callback,
+                                     NMNewSecretsRequestedFunc callback,
                                      gpointer callback_data,
                                      gpointer user_data)
 {
-	NMAGConfSettings *self = NMA_GCONF_SETTINGS (user_data);
+	NMGConfSettings *self = NM_GCONF_SETTINGS (user_data);
 
 	/* Re-emit the signal to listeners so they don't have to know about
 	 * every single connection
@@ -86,20 +87,20 @@ connection_new_secrets_requested_cb (NMAGConfConnection *connection,
 static void
 connection_removed (NMExportedConnection *connection, gpointer user_data)
 {
-	NMAGConfSettingsPrivate *priv = NMA_GCONF_SETTINGS_GET_PRIVATE (user_data);
+	NMGConfSettingsPrivate *priv = NM_GCONF_SETTINGS_GET_PRIVATE (user_data);
 
 	priv->connections = g_slist_remove (priv->connections, connection);
 	g_object_unref (connection);
 }
 
 static void
-internal_add_connection (NMAGConfSettings *self, NMAGConfConnection *connection)
+internal_add_connection (NMGConfSettings *self, NMGConfConnection *connection)
 {
-	NMAGConfSettingsPrivate *priv = NMA_GCONF_SETTINGS_GET_PRIVATE (self);
+	NMGConfSettingsPrivate *priv = NM_GCONF_SETTINGS_GET_PRIVATE (self);
 	DBusGConnection *bus = NULL;
 
 	g_return_if_fail (connection != NULL);
-	g_return_if_fail (NMA_IS_GCONF_CONNECTION (connection));
+	g_return_if_fail (NM_IS_GCONF_CONNECTION (connection));
 
 	priv->connections = g_slist_prepend (priv->connections, connection);
 	g_signal_connect (connection, "new-secrets-requested",
@@ -115,8 +116,11 @@ internal_add_connection (NMAGConfSettings *self, NMAGConfConnection *connection)
 		dbus_g_connection_unref (bus);
 	}
 
-	g_signal_emit_by_name (self, NM_SETTINGS_INTERFACE_NEW_CONNECTION, NM_CONNECTION (connection));
-	g_return_if_fail (NMA_IS_GCONF_CONNECTION (priv->connections->data));
+	if (!priv->reading_connections)
+		/* Don't emit the signal when doing the initial population */
+		g_signal_emit_by_name (self, NM_SETTINGS_INTERFACE_NEW_CONNECTION, NM_CONNECTION (connection));
+
+	g_return_if_fail (NM_IS_GCONF_CONNECTION (priv->connections->data));
 }
 
 static void
@@ -127,24 +131,24 @@ update_cb (NMSettingsConnectionInterface *connection,
 	if (error) {
 		g_warning ("%s: %s:%d error updating connection %s: (%d) %s",
 		           __func__, __FILE__, __LINE__,
-		           nma_gconf_connection_get_gconf_path (NMA_GCONF_CONNECTION (connection)),
+		           nm_gconf_connection_get_gconf_path (NM_GCONF_CONNECTION (connection)),
 		           error ? error->code : -1,
 		           (error && error->message) ? error->message : "(unknown)");
 	}
 }
 
-NMAGConfConnection *
-nma_gconf_settings_add_connection (NMAGConfSettings *self, NMConnection *connection)
+NMGConfConnection *
+nm_gconf_settings_add_connection (NMGConfSettings *self, NMConnection *connection)
 {
-	NMAGConfSettingsPrivate *priv;
-	NMAGConfConnection *exported;
+	NMGConfSettingsPrivate *priv;
+	NMGConfConnection *exported;
 	guint32 i = 0;
 	char *path = NULL;
 
-	g_return_val_if_fail (NMA_IS_GCONF_SETTINGS (self), NULL);
+	g_return_val_if_fail (NM_IS_GCONF_SETTINGS (self), NULL);
 	g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL);
 
-	priv = NMA_GCONF_SETTINGS_GET_PRIVATE (self);
+	priv = NM_GCONF_SETTINGS_GET_PRIVATE (self);
 
 	/* Find free GConf directory */
 	while (i++ < G_MAXUINT32) {
@@ -162,7 +166,7 @@ nma_gconf_settings_add_connection (NMAGConfSettings *self, NMConnection *connect
 		return NULL;
 	}
 
-	exported = nma_gconf_connection_new_from_connection (priv->client, path, connection);
+	exported = nm_gconf_connection_new_from_connection (priv->client, path, connection);
 	g_free (path);
 	if (exported) {
 		internal_add_connection (self, exported);
@@ -183,7 +187,7 @@ add_connection (NMSettingsService *settings,
                 NMSettingsAddConnectionFunc callback,
                 gpointer user_data)
 {
-	NMAGConfSettings *self = NMA_GCONF_SETTINGS (settings);
+	NMGConfSettings *self = NM_GCONF_SETTINGS (settings);
 
 	/* For now, we don't support additions via D-Bus until we figure out
 	 * the security implications.
@@ -197,25 +201,25 @@ add_connection (NMSettingsService *settings,
 		return;
 	}
 
-	nma_gconf_settings_add_connection (self, connection);
+	nm_gconf_settings_add_connection (self, connection);
 	callback (NM_SETTINGS_INTERFACE (settings), NULL, user_data);
 }
 
-static NMAGConfConnection *
-get_connection_by_gconf_path (NMAGConfSettings *self, const char *path)
+static NMGConfConnection *
+get_connection_by_gconf_path (NMGConfSettings *self, const char *path)
 {
-	NMAGConfSettingsPrivate *priv;
+	NMGConfSettingsPrivate *priv;
 	GSList *iter;
 
-	g_return_val_if_fail (NMA_IS_GCONF_SETTINGS (self), NULL);
+	g_return_val_if_fail (NM_IS_GCONF_SETTINGS (self), NULL);
 	g_return_val_if_fail (path != NULL, NULL);
 
-	priv = NMA_GCONF_SETTINGS_GET_PRIVATE (self);
+	priv = NM_GCONF_SETTINGS_GET_PRIVATE (self);
 	for (iter = priv->connections; iter; iter = iter->next) {
-		NMAGConfConnection *connection = NMA_GCONF_CONNECTION (iter->data);
+		NMGConfConnection *connection = NM_GCONF_CONNECTION (iter->data);
 		const char *gconf_path;
 
-		gconf_path = nma_gconf_connection_get_gconf_path (connection);
+		gconf_path = nm_gconf_connection_get_gconf_path (connection);
 		if (gconf_path && !strcmp (gconf_path, path))
 			return connection;
 	}
@@ -224,9 +228,9 @@ get_connection_by_gconf_path (NMAGConfSettings *self, const char *path)
 }
 
 static void
-read_connections (NMAGConfSettings *settings)
+read_connections (NMGConfSettings *settings)
 {
-	NMAGConfSettingsPrivate *priv = NMA_GCONF_SETTINGS_GET_PRIVATE (settings);
+	NMGConfSettingsPrivate *priv = NM_GCONF_SETTINGS_GET_PRIVATE (settings);
 	GSList *dir_list;
 	GSList *iter;
 
@@ -234,16 +238,20 @@ read_connections (NMAGConfSettings *settings)
 	if (!dir_list)
 		return;
 
+	priv->reading_connections = TRUE;
+
 	for (iter = dir_list; iter; iter = iter->next) {
 		char *dir = (char *) iter->data;
-		NMAGConfConnection *connection;
+		NMGConfConnection *connection;
 
-		connection = nma_gconf_connection_new (priv->client, dir);
+		connection = nm_gconf_connection_new (priv->client, dir);
 		if (connection)
 			internal_add_connection (settings, connection);
 		g_free (dir);
 	}
 
+	priv->reading_connections = FALSE;
+
 	g_slist_free (dir_list);
 	priv->connections = g_slist_reverse (priv->connections);
 }
@@ -251,8 +259,8 @@ read_connections (NMAGConfSettings *settings)
 static gboolean
 read_connections_cb (gpointer data)
 {
-	NMA_GCONF_SETTINGS_GET_PRIVATE (data)->read_connections_id = 0;
-	read_connections (NMA_GCONF_SETTINGS (data));
+	NM_GCONF_SETTINGS_GET_PRIVATE (data)->read_connections_id = 0;
+	read_connections (NM_GCONF_SETTINGS (data));
 
 	return FALSE;
 }
@@ -260,20 +268,20 @@ read_connections_cb (gpointer data)
 static GSList *
 list_connections (NMSettingsService *settings)
 {
-	NMAGConfSettingsPrivate *priv = NMA_GCONF_SETTINGS_GET_PRIVATE (settings);
+	NMGConfSettingsPrivate *priv = NM_GCONF_SETTINGS_GET_PRIVATE (settings);
 
 	if (priv->read_connections_id) {
 		g_source_remove (priv->read_connections_id);
 		priv->read_connections_id = 0;
 
-		read_connections (NMA_GCONF_SETTINGS (settings));
+		read_connections (NM_GCONF_SETTINGS (settings));
 	}
 
 	return g_slist_copy (priv->connections);
 }
 
 typedef struct {
-	NMAGConfSettings *settings;
+	NMGConfSettings *settings;
 	char *path;
 } ConnectionChangedInfo;
 
@@ -290,19 +298,19 @@ static gboolean
 connection_changes_done (gpointer data)
 {
 	ConnectionChangedInfo *info = (ConnectionChangedInfo *) data;
-	NMAGConfSettingsPrivate *priv = NMA_GCONF_SETTINGS_GET_PRIVATE (info->settings);
-	NMAGConfConnection *connection;
+	NMGConfSettingsPrivate *priv = NM_GCONF_SETTINGS_GET_PRIVATE (info->settings);
+	NMGConfConnection *connection;
 
 	connection = get_connection_by_gconf_path (info->settings, info->path);
 	if (!connection) {
 		/* New connection */
-		connection = nma_gconf_connection_new (priv->client, info->path);
+		connection = nm_gconf_connection_new (priv->client, info->path);
 		if (connection)
 			internal_add_connection (info->settings, connection);
 	} else {
 		if (gconf_client_dir_exists (priv->client, info->path, NULL)) {
 			/* Updated connection */
-			if (!nma_gconf_connection_gconf_changed (connection))
+			if (!nm_gconf_connection_gconf_changed (connection))
 				priv->connections = g_slist_remove (priv->connections, connection);
 		}
 	}
@@ -318,8 +326,8 @@ connections_changed_cb (GConfClient *conf_client,
                         GConfEntry *entry,
                         gpointer user_data)
 {
-	NMAGConfSettings *self = NMA_GCONF_SETTINGS (user_data);
-	NMAGConfSettingsPrivate *priv = NMA_GCONF_SETTINGS_GET_PRIVATE (self);
+	NMGConfSettings *self = NM_GCONF_SETTINGS (user_data);
+	NMGConfSettingsPrivate *priv = NM_GCONF_SETTINGS_GET_PRIVATE (self);
 	char **dirs = NULL;
 	guint len;
 	char *path = NULL;
@@ -330,9 +338,9 @@ connections_changed_cb (GConfClient *conf_client,
 		goto out;
 
 	if (   strcmp (dirs[0], "")
-	    || strcmp (dirs[1], "system")
-	    || strcmp (dirs[2], "networking")
-	    || strcmp (dirs[3], "connections"))
+		   || strcmp (dirs[1], "system")
+		   || strcmp (dirs[2], "networking")
+		   || strcmp (dirs[3], "connections"))
 		goto out;
 
 	path = g_strconcat ("/", dirs[1], "/", dirs[2], "/", dirs[3], "/", dirs[4], NULL);
@@ -347,11 +355,11 @@ connections_changed_cb (GConfClient *conf_client,
 		path = NULL;
 
 		id = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE, connection_changes_done, 
-						  info, connection_changed_info_destroy);
+							  info, connection_changed_info_destroy);
 		g_hash_table_insert (priv->pending_changes, info->path, GUINT_TO_POINTER (id));
 	}
 
-out:
+ out:
 	g_free (path);
 	g_strfreev (dirs);
 }
@@ -365,9 +373,9 @@ remove_pending_change (gpointer data)
 /************************************************************/
 
 static void
-nma_gconf_settings_init (NMAGConfSettings *self)
+nm_gconf_settings_init (NMGConfSettings *self)
 {
-	NMAGConfSettingsPrivate *priv = NMA_GCONF_SETTINGS_GET_PRIVATE (self);
+	NMGConfSettingsPrivate *priv = NM_GCONF_SETTINGS_GET_PRIVATE (self);
 
 	priv->client = gconf_client_get_default ();
 	priv->pending_changes = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, remove_pending_change);
@@ -386,21 +394,21 @@ nma_gconf_settings_init (NMAGConfSettings *self)
 
 static GObject *
 constructor (GType type,
-		   guint n_construct_params,
-		   GObjectConstructParam *construct_params)
+			 guint n_construct_params,
+			 GObjectConstructParam *construct_params)
 {
 	GObject *object;
 
-	object = G_OBJECT_CLASS (nma_gconf_settings_parent_class)->constructor (type, n_construct_params, construct_params);
+	object = G_OBJECT_CLASS (nm_gconf_settings_parent_class)->constructor (type, n_construct_params, construct_params);
 	if (object)
-		NMA_GCONF_SETTINGS_GET_PRIVATE (object)->read_connections_id = g_idle_add (read_connections_cb, object);
+		NM_GCONF_SETTINGS_GET_PRIVATE (object)->read_connections_id = g_idle_add (read_connections_cb, object);
 	return object;
 }
 
 static void
 dispose (GObject *object)
 {
-	NMAGConfSettingsPrivate *priv = NMA_GCONF_SETTINGS_GET_PRIVATE (object);
+	NMGConfSettingsPrivate *priv = NM_GCONF_SETTINGS_GET_PRIVATE (object);
 
 	if (priv->disposed)
 		return;
@@ -422,16 +430,16 @@ dispose (GObject *object)
 
 	g_object_unref (priv->client);
 
-	G_OBJECT_CLASS (nma_gconf_settings_parent_class)->dispose (object);
+	G_OBJECT_CLASS (nm_gconf_settings_parent_class)->dispose (object);
 }
 
 static void
-nma_gconf_settings_class_init (NMAGConfSettingsClass *class)
+nm_gconf_settings_class_init (NMGConfSettingsClass *class)
 {
 	GObjectClass *object_class = G_OBJECT_CLASS (class);
 	NMSettingsServiceClass *settings_class = NM_SETTINGS_SERVICE_CLASS (class);
 
-	g_type_class_add_private (class, sizeof (NMAGConfSettingsPrivate));
+	g_type_class_add_private (class, sizeof (NMGConfSettingsPrivate));
 
 	/* Virtual methods */
 	object_class->constructor = constructor;
@@ -443,11 +451,11 @@ nma_gconf_settings_class_init (NMAGConfSettingsClass *class)
 	/* Signals */
 	signals[NEW_SECRETS_REQUESTED] =
 		g_signal_new ("new-secrets-requested",
-				    G_OBJECT_CLASS_TYPE (object_class),
-				    G_SIGNAL_RUN_FIRST,
-				    G_STRUCT_OFFSET (NMAGConfSettingsClass, new_secrets_requested),
-				    NULL, NULL,
-				    nma_marshal_VOID__OBJECT_STRING_POINTER_BOOLEAN_POINTER_POINTER,
-				    G_TYPE_NONE, 6,
-				    G_TYPE_OBJECT, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_BOOLEAN, G_TYPE_POINTER, G_TYPE_POINTER);
+					  G_OBJECT_CLASS_TYPE (object_class),
+					  G_SIGNAL_RUN_FIRST,
+					  G_STRUCT_OFFSET (NMGConfSettingsClass, new_secrets_requested),
+					  NULL, NULL,
+					  nma_marshal_VOID__OBJECT_STRING_POINTER_BOOLEAN_POINTER_POINTER,
+					  G_TYPE_NONE, 6,
+					  G_TYPE_OBJECT, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_BOOLEAN, G_TYPE_POINTER, G_TYPE_POINTER);
 }
diff --git a/src/gconf-helpers/nma-gconf-settings.h b/libnm-gtk/nm-gconf-settings.h
similarity index 51%
rename from src/gconf-helpers/nma-gconf-settings.h
rename to libnm-gtk/nm-gconf-settings.h
index d197a35..f1e6497 100644
--- a/src/gconf-helpers/nma-gconf-settings.h
+++ b/libnm-gtk/nm-gconf-settings.h
@@ -18,47 +18,47 @@
  * (C) Copyright 2008 Novell, Inc.
  */
 
-#ifndef NMA_GCONF_SETTINGS_H
-#define NMA_GCONF_SETTINGS_H
+#ifndef NM_GCONF_SETTINGS_H
+#define NM_GCONF_SETTINGS_H
 
 #include <nm-connection.h>
 #include <nm-settings-service.h>
 
-#include "nma-gconf-connection.h"
+#include "nm-gconf-connection.h"
 
 G_BEGIN_DECLS
 
-#define NMA_TYPE_GCONF_SETTINGS            (nma_gconf_settings_get_type ())
-#define NMA_GCONF_SETTINGS(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMA_TYPE_GCONF_SETTINGS, NMAGConfSettings))
-#define NMA_GCONF_SETTINGS_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), NMA_TYPE_GCONF_SETTINGS, NMAGConfSettingsClass))
-#define NMA_IS_GCONF_SETTINGS(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMA_TYPE_GCONF_SETTINGS))
-#define NMA_IS_GCONF_SETTINGS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NMA_TYPE_GCONF_SETTINGS))
-#define NMA_GCONF_SETTINGS_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NMA_TYPE_GCONF_SETTINGS, NMAGConfSettingsClass))
+#define NM_TYPE_GCONF_SETTINGS            (nm_gconf_settings_get_type ())
+#define NM_GCONF_SETTINGS(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_GCONF_SETTINGS, NMGConfSettings))
+#define NM_GCONF_SETTINGS_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_GCONF_SETTINGS, NMGConfSettingsClass))
+#define NM_IS_GCONF_SETTINGS(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_GCONF_SETTINGS))
+#define NM_IS_GCONF_SETTINGS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NM_TYPE_GCONF_SETTINGS))
+#define NM_GCONF_SETTINGS_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_GCONF_SETTINGS, NMGConfSettingsClass))
 
 typedef struct {
 	NMSettingsService parent;
-} NMAGConfSettings;
+} NMGConfSettings;
 
 typedef struct {
 	NMSettingsServiceClass parent;
 
 	/* Signals */
-	void (*new_secrets_requested) (NMAGConfSettings *self,
-	                               NMAGConfConnection *exported,
+	void (*new_secrets_requested) (NMGConfSettings *self,
+	                               NMGConfConnection *exported,
 	                               const char *setting_name,
 	                               const char **hints,
 	                               gboolean ask_user,
-	                               NMANewSecretsRequestedFunc callback,
+	                               NMNewSecretsRequestedFunc callback,
 	                               gpointer callback_data);
-} NMAGConfSettingsClass;
+} NMGConfSettingsClass;
 
-GType nma_gconf_settings_get_type (void);
+GType nm_gconf_settings_get_type (void);
 
-NMAGConfSettings *nma_gconf_settings_new (DBusGConnection *bus);
+NMGConfSettings *nm_gconf_settings_new (DBusGConnection *bus);
 
-NMAGConfConnection *nma_gconf_settings_add_connection (NMAGConfSettings *self,
-                                                       NMConnection *connection);
+NMGConfConnection *nm_gconf_settings_add_connection (NMGConfSettings *self,
+													 NMConnection *connection);
 
 G_END_DECLS
 
-#endif /* NMA_GCONF_SETTINGS_H */
+#endif /* NM_GCONF_SETTINGS_H */
diff --git a/libnm-gtk/nm-gsm-item.c b/libnm-gtk/nm-gsm-item.c
new file mode 100644
index 0000000..e3cffc9
--- /dev/null
+++ b/libnm-gtk/nm-gsm-item.c
@@ -0,0 +1,76 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2009 Novell, Inc.
+ */
+
+#include <glib/gi18n.h>
+#include <nm-setting-8021x.h>
+#include "nm-gsm-item.h"
+
+G_DEFINE_TYPE (NMGsmItem, nm_gsm_item, NM_TYPE_DEVICE_ITEM)
+
+NMListItem *
+nm_gsm_item_new (NMClient *client,
+                 NMGsmDevice *device,
+                 NMSettingsConnectionInterface *connection)
+{
+    g_return_val_if_fail (NM_IS_CLIENT (client), NULL);
+    g_return_val_if_fail (NM_IS_GSM_DEVICE (device), NULL);
+    g_return_val_if_fail (NM_IS_SETTINGS_CONNECTION_INTERFACE (connection), NULL);
+
+    return (NMListItem *) g_object_new (NM_TYPE_GSM_ITEM,
+                                        NM_LIST_ITEM_TYPE_NAME, _("3G"),
+                                        NM_CONNECTION_ITEM_CLIENT, client,
+                                        NM_CONNECTION_ITEM_CONNECTION, connection,
+                                        NM_DEVICE_ITEM_DEVICE, device,
+                                        NULL);
+}
+
+static int
+priority (NMListItem *item)
+{
+    return NM_LIST_ITEM_PRIORITY_DEV_GSM + NM_LIST_ITEM_CLASS (nm_gsm_item_parent_class)->priority (item);
+}
+
+/*****************************************************************************/
+
+static void
+notify (GObject *object, GParamSpec *spec)
+{
+    /* If the connection is removed from the item, request deletion */
+    if (spec && !g_strcmp0 (spec->name, NM_CONNECTION_ITEM_CONNECTION) && 
+        !nm_connection_item_get_connection (NM_CONNECTION_ITEM (object)))
+
+        nm_list_item_request_remove (NM_LIST_ITEM (object));
+}
+
+static void
+nm_gsm_item_init (NMGsmItem *self)
+{
+    g_object_set (self, NM_LIST_ITEM_ICON, "nm-device-wwan", NULL);
+}
+
+static void
+nm_gsm_item_class_init (NMGsmItemClass *klass)
+{
+    GObjectClass *object_class = G_OBJECT_CLASS (klass);
+    NMListItemClass *list_class = NM_LIST_ITEM_CLASS (klass);
+
+    object_class->notify = notify;
+
+    list_class->priority = priority;
+}
diff --git a/libnm-gtk/nm-gsm-item.h b/libnm-gtk/nm-gsm-item.h
new file mode 100644
index 0000000..5ea92c7
--- /dev/null
+++ b/libnm-gtk/nm-gsm-item.h
@@ -0,0 +1,52 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2009 Novell, Inc.
+ */
+
+#ifndef NM_GSM_ITEM_H
+#define NM_GSM_ITEM_H
+
+#include <glib-object.h>
+#include <nm-gsm-device.h>
+#include <nm-device-item.h>
+
+G_BEGIN_DECLS
+
+#define NM_TYPE_GSM_ITEM            (nm_gsm_item_get_type ())
+#define NM_GSM_ITEM(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_GSM_ITEM, NMGsmItem))
+#define NM_GSM_ITEM_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_GSM_ITEM, NMGsmItemClass))
+#define NM_IS_GSM_ITEM(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_GSM_ITEM))
+#define NM_IS_GSM_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NM_TYPE_GSM_ITEM))
+#define NM_GSM_ITEM_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_GSM_ITEM, NMGsmItemClass))
+
+typedef struct {
+    NMDeviceItem parent;
+} NMGsmItem;
+
+typedef struct {
+    NMDeviceItemClass parent_class;
+} NMGsmItemClass;
+
+GType nm_gsm_item_get_type (void);
+
+NMListItem *nm_gsm_item_new (NMClient *client,
+                             NMGsmDevice *device,
+                             NMSettingsConnectionInterface *connection);
+
+G_END_DECLS
+
+#endif /* NM_GSM_ITEM_H */
diff --git a/libnm-gtk/nm-gsm-provider.c b/libnm-gtk/nm-gsm-provider.c
new file mode 100644
index 0000000..859c488
--- /dev/null
+++ b/libnm-gtk/nm-gsm-provider.c
@@ -0,0 +1,71 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2009 Novell, Inc.
+ */
+
+#include "nm-gsm-provider.h"
+#include "nm-gsm-item.h"
+#include "utils.h"
+
+G_DEFINE_TYPE (NMGsmProvider, nm_gsm_provider, NM_TYPE_DEVICE_PROVIDER)
+
+NMItemProvider *
+nm_gsm_provider_new (NMClient *client,
+                     NMGsmDevice *device)
+{
+    g_return_val_if_fail (NM_IS_CLIENT (client), NULL);
+    g_return_val_if_fail (NM_IS_GSM_DEVICE (device), NULL);
+
+    return (NMItemProvider *) g_object_new (NM_TYPE_GSM_PROVIDER,
+                                            NM_ITEM_PROVIDER_CLIENT, client,
+                                            NM_DEVICE_PROVIDER_DEVICE, device,
+                                            NULL);
+}
+
+static void
+gsm_added (NMItemProvider *provider,
+           NMSettingsConnectionInterface *connection)
+{
+    NMDeviceProvider *device_provider = NM_DEVICE_PROVIDER (provider);
+    NMDevice *device;
+
+    if (!nm_device_provider_ready (device_provider))
+        return;
+
+    device = nm_device_provider_get_device (device_provider);
+    if (utils_connection_valid_for_device (NM_CONNECTION (connection), device, NULL)) {
+        NMListItem *item;
+
+        item = nm_gsm_item_new (nm_item_provider_get_client (provider), NM_GSM_DEVICE (device), connection);
+        nm_item_provider_item_added (provider, item);
+    }
+}
+
+/*****************************************************************************/
+
+static void
+nm_gsm_provider_init (NMGsmProvider *self)
+{
+}
+
+static void
+nm_gsm_provider_class_init (NMGsmProviderClass *klass)
+{
+    NMItemProviderClass *item_class = NM_ITEM_PROVIDER_CLASS (klass);
+
+    item_class->connection_added = gsm_added;
+}
diff --git a/libnm-gtk/nm-gsm-provider.h b/libnm-gtk/nm-gsm-provider.h
new file mode 100644
index 0000000..c497b10
--- /dev/null
+++ b/libnm-gtk/nm-gsm-provider.h
@@ -0,0 +1,51 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2009 Novell, Inc.
+ */
+
+#ifndef NM_GSM_PROVIDER_H
+#define NM_GSM_PROVIDER_H
+
+#include <glib-object.h>
+#include <nm-gsm-device.h>
+#include <nm-device-provider.h>
+
+G_BEGIN_DECLS
+
+#define NM_TYPE_GSM_PROVIDER            (nm_gsm_provider_get_type ())
+#define NM_GSM_PROVIDER(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_GSM_PROVIDER, NMGsmProvider))
+#define NM_GSM_PROVIDER_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_GSM_PROVIDER, NMGsmProviderClass))
+#define NM_IS_GSM_PROVIDER(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_GSM_PROVIDER))
+#define NM_IS_GSM_PROVIDER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NM_TYPE_GSM_PROVIDER))
+#define NM_GSM_PROVIDER_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_GSM_PROVIDER, NMGsmProviderClass))
+
+typedef struct {
+    NMDeviceProvider parent;
+} NMGsmProvider;
+
+typedef struct {
+    NMDeviceProviderClass parent_class;
+} NMGsmProviderClass;
+
+GType nm_gsm_provider_get_type (void);
+
+NMItemProvider *nm_gsm_provider_new (NMClient *client,
+                                     NMGsmDevice *device);
+
+G_END_DECLS
+
+#endif /* NM_GSM_PROVIDER_H */
diff --git a/src/nmn-icon-cache.c b/libnm-gtk/nm-icon-cache.c
similarity index 73%
rename from src/nmn-icon-cache.c
rename to libnm-gtk/nm-icon-cache.c
index 9aacbd2..d0a3427 100644
--- a/src/nmn-icon-cache.c
+++ b/libnm-gtk/nm-icon-cache.c
@@ -18,13 +18,13 @@
  */
 
 #include <gtk/gtk.h>
-#include "nmn-icon-cache.h"
+#include "nm-icon-cache.h"
 
 static GtkIconTheme *icon_theme = NULL;
 static GHashTable *cache = NULL;
 
 void
-nmn_icon_cache_invalidate (void)
+nm_icon_cache_invalidate (void)
 {
     if (cache) {
         g_hash_table_destroy (cache);
@@ -35,18 +35,38 @@ nmn_icon_cache_invalidate (void)
         icon_theme = NULL;
 }
 
+static void
+init_icon_theme (void)
+{
+    char **path = NULL;
+    int n_path;
+    int i;
+
+    icon_theme = gtk_icon_theme_get_default ();
+    g_signal_connect (icon_theme, "changed", G_CALLBACK (nm_icon_cache_invalidate), NULL);
+
+    gtk_icon_theme_get_search_path (icon_theme, &path, &n_path);
+    for (i = n_path - 1; i >= 0; i--) {
+        if (g_strcmp0 (ICONDIR, path[i]) == 0)
+            break;
+    }
+
+    if (i < 0)
+        gtk_icon_theme_append_search_path (icon_theme, ICONDIR);
+
+    g_strfreev (path);
+}
+
 GdkPixbuf *
-nmn_icon_cache_get (const char *icon_name)
+nm_icon_cache_get (const char *icon_name)
 {
     GdkPixbuf *pixbuf;
     GError *error = NULL;
 
     g_return_val_if_fail (icon_name != NULL, NULL);
 
-    if (G_UNLIKELY (icon_theme == NULL)) {
-        icon_theme = gtk_icon_theme_get_for_screen (gdk_screen_get_default ());
-        g_signal_connect (icon_theme, "changed", G_CALLBACK (nmn_icon_cache_invalidate), NULL);
-    }
+    if (G_UNLIKELY (icon_theme == NULL))
+        init_icon_theme ();
 
     if (G_UNLIKELY (cache == NULL)) {
         cache = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
@@ -55,14 +75,13 @@ nmn_icon_cache_get (const char *icon_name)
         pixbuf = (GdkPixbuf *) g_hash_table_lookup (cache, icon_name);
 
     if (!pixbuf) {
-        /* Prefer theme icons */
         pixbuf = gtk_icon_theme_load_icon (icon_theme, icon_name, 48, 0, &error);
 
         if (!pixbuf) {
             /* Try harder, using our own icons if theme doesn't provide something */
             char *path;
 
-            path = g_strconcat (ICON_PATH, icon_name, ".png", NULL);
+            path = g_strconcat (ICONDIR, icon_name, ".png", NULL);
             pixbuf = gdk_pixbuf_new_from_file (path, NULL);
             g_free (path);
         }
diff --git a/src/nmn-icon-cache.h b/libnm-gtk/nm-icon-cache.h
similarity index 82%
rename from src/nmn-icon-cache.h
rename to libnm-gtk/nm-icon-cache.h
index ddf6818..92f6354 100644
--- a/src/nmn-icon-cache.h
+++ b/libnm-gtk/nm-icon-cache.h
@@ -17,12 +17,12 @@
  * (C) Copyright 2009 Novell, Inc.
  */
 
-#ifndef NMN_ICON_CACHE_H
-#define NMN_ICON_CACHE_H
+#ifndef NM_ICON_CACHE_H
+#define NM_ICON_CACHE_H
 
 #include <gdk-pixbuf/gdk-pixbuf.h>
 
-GdkPixbuf *nmn_icon_cache_get        (const char *icon_name);
-void       nmn_icon_cache_invalidate (void);
+GdkPixbuf *nm_icon_cache_get        (const char *icon_name);
+void       nm_icon_cache_invalidate (void);
 
-#endif /* NMN_ICON_CACHE_H */
+#endif /* NM_ICON_CACHE_H */
diff --git a/libnm-gtk/nm-item-provider.c b/libnm-gtk/nm-item-provider.c
new file mode 100644
index 0000000..80bb2e4
--- /dev/null
+++ b/libnm-gtk/nm-item-provider.c
@@ -0,0 +1,308 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2009 Novell, Inc.
+ */
+
+
+#include <nm-setting-connection.h>
+#include "nm-item-provider.h"
+
+G_DEFINE_ABSTRACT_TYPE (NMItemProvider, nm_item_provider, G_TYPE_OBJECT)
+
+enum {
+    PROP_0,
+    PROP_CLIENT,
+
+    LAST_PROP
+};
+
+enum {
+	ITEM_ADDED,
+    ITEM_CHANGED,
+	ITEM_REMOVED,
+
+	LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+#define GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), NM_TYPE_ITEM_PROVIDER, NMItemProviderPrivate))
+
+typedef struct {
+    NMClient *client;
+    GSList *settings;
+
+    GSList *items;
+
+    gboolean disposed;
+} NMItemProviderPrivate;
+
+static void
+item_changed (NMListItem *item,
+              GParamSpec *pspec,
+              gpointer user_data)
+{
+    g_signal_emit (user_data, signals[ITEM_CHANGED], 0, item);
+}
+
+static void
+remove_item (NMListItem *item,
+             gpointer user_data)
+{
+    NMItemProvider *self = NM_ITEM_PROVIDER (user_data);
+    NMItemProviderPrivate *priv = GET_PRIVATE (self);
+    GSList *link;
+
+    link = g_slist_find (priv->items, item);
+    if (link) {
+        g_signal_handlers_disconnect_matched (item, G_SIGNAL_MATCH_DATA,
+                                              0, 0, NULL, NULL, user_data);
+
+        priv->items = g_slist_delete_link (priv->items, link);
+        g_signal_emit (self, signals[ITEM_REMOVED], 0, item);
+        g_object_unref (item);
+    }
+}
+
+void
+nm_item_provider_item_added (NMItemProvider *provider,
+                             NMListItem *item)
+{
+    NMItemProviderPrivate *priv;
+
+    g_return_if_fail (NM_IS_ITEM_PROVIDER (provider));
+    g_return_if_fail (NM_IS_LIST_ITEM (item));
+
+    priv = GET_PRIVATE (provider);
+    priv->items = g_slist_prepend (priv->items, g_object_ref_sink (item));
+    g_signal_connect (item, "request-remove", G_CALLBACK (remove_item), provider);
+    g_signal_connect (item, "notify", G_CALLBACK (item_changed), provider);
+
+    g_signal_emit (provider, signals[ITEM_ADDED], 0, item);
+}
+
+static void
+connection_added (NMSettingsInterface *settings,
+                  NMSettingsConnectionInterface *connection,
+                  gpointer data)
+{
+    NMItemProvider *self = NM_ITEM_PROVIDER (data);
+    NMSettingConnection *s_con;
+
+    s_con = (NMSettingConnection *) nm_connection_get_setting (NM_CONNECTION (connection), NM_TYPE_SETTING_CONNECTION);
+    g_debug ("Connection '%s' (%d) added", nm_setting_connection_get_id (s_con),
+             nm_connection_get_scope (NM_CONNECTION (connection)));
+
+    if (NM_ITEM_PROVIDER_GET_CLASS (self)->connection_added)
+        NM_ITEM_PROVIDER_GET_CLASS (self)->connection_added (self, connection);
+}
+
+static void
+add_settings_connections (NMSettingsInterface *settings,
+                          NMItemProvider *self)
+{
+    GSList *items;
+    GSList *iter;
+
+    items = nm_settings_interface_list_connections (settings);
+    for (iter = items; iter; iter = iter->next)
+        connection_added (settings, NM_SETTINGS_CONNECTION_INTERFACE (iter->data), self);
+
+    g_slist_free (items);
+}
+
+void
+nm_item_provider_add_settings (NMItemProvider *self,
+                               NMSettingsInterface *settings)
+{
+    NMItemProviderPrivate *priv;
+
+    g_return_if_fail (NM_IS_ITEM_PROVIDER (self));
+    g_return_if_fail (NM_IS_SETTINGS_INTERFACE (settings));
+
+    priv = GET_PRIVATE (self);
+
+    priv->settings = g_slist_prepend (priv->settings, g_object_ref (settings));
+    g_signal_connect (settings, "new-connection", G_CALLBACK (connection_added), self);
+    add_settings_connections (settings, self);
+}
+
+NMClient *
+nm_item_provider_get_client (NMItemProvider *self)
+{
+    g_return_val_if_fail (NM_IS_ITEM_PROVIDER (self), NULL);
+
+    return GET_PRIVATE (self)->client;
+}
+
+GSList *
+nm_item_provider_get_connections (NMItemProvider *self)
+{
+    NMItemProviderPrivate *priv;
+    GSList *iter;
+    GSList *list = NULL;
+
+    g_return_val_if_fail (NM_IS_ITEM_PROVIDER (self), NULL);
+
+    priv = GET_PRIVATE (self);
+    for (iter = priv->settings; iter; iter = iter->next)
+        list = g_slist_concat (list, nm_settings_interface_list_connections (NM_SETTINGS_INTERFACE (iter->data)));
+
+    return list;
+}
+
+GSList *
+nm_item_provider_get_items (NMItemProvider *self)
+{
+    g_return_val_if_fail (NM_IS_ITEM_PROVIDER (self), NULL);
+
+    return GET_PRIVATE (self)->items;
+}
+
+void
+nm_item_provider_clear (NMItemProvider *self)
+{
+    NMItemProviderPrivate *priv;
+
+    g_return_if_fail (NM_IS_ITEM_PROVIDER (self));
+
+    priv = GET_PRIVATE (self);
+    g_slist_foreach (priv->items, (GFunc) remove_item, self);
+}
+
+void
+nm_item_provider_reset (NMItemProvider *self)
+{
+    NMItemProviderPrivate *priv;
+
+    g_return_if_fail (NM_IS_ITEM_PROVIDER (self));
+
+    priv = GET_PRIVATE (self);
+    g_slist_foreach (priv->settings, (GFunc) add_settings_connections, self);
+}
+
+/*****************************************************************************/
+
+static void
+nm_item_provider_init (NMItemProvider *self)
+{
+}
+
+static void
+set_property (GObject *object, guint prop_id,
+              const GValue *value, GParamSpec *pspec)
+{
+    NMItemProviderPrivate *priv = GET_PRIVATE (object);
+
+    switch (prop_id) {
+    case PROP_CLIENT:
+        /* Construct only */
+        priv->client = 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)
+{
+    NMItemProviderPrivate *priv = GET_PRIVATE (object);
+
+    switch (prop_id) {
+    case PROP_CLIENT:
+        g_value_set_object (value, priv->client);
+        break;
+    default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+        break;
+    }
+}
+
+static void
+dispose (GObject *object)
+{
+    NMItemProviderPrivate *priv = GET_PRIVATE (object);
+
+    if (!priv->disposed) {
+        nm_item_provider_clear (NM_ITEM_PROVIDER (object));
+
+        g_slist_foreach (priv->settings, (GFunc) g_object_unref, NULL);
+        g_slist_free (priv->settings);
+
+        if (priv->client)
+            g_object_unref (priv->client);
+
+        priv->disposed = TRUE;
+    }
+
+    G_OBJECT_CLASS (nm_item_provider_parent_class)->dispose (object);
+}
+
+static void
+nm_item_provider_class_init (NMItemProviderClass *klass)
+{
+    GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+    g_type_class_add_private (object_class, sizeof (NMItemProviderPrivate));
+
+    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_CLIENT,
+         g_param_spec_object (NM_ITEM_PROVIDER_CLIENT,
+                              "NMClient",
+                              "NMClient",
+                              NM_TYPE_CLIENT,
+                              G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+    signals[ITEM_ADDED] =
+		g_signal_new ("item-added",
+					  G_OBJECT_CLASS_TYPE (object_class),
+					  G_SIGNAL_RUN_FIRST,
+					  G_STRUCT_OFFSET (NMItemProviderClass, item_added),
+					  NULL, NULL,
+					  g_cclosure_marshal_VOID__OBJECT,
+					  G_TYPE_NONE, 1,
+					  NM_TYPE_LIST_ITEM);
+
+    /* Signals */
+    signals[ITEM_CHANGED] =
+		g_signal_new ("item-changed",
+					  G_OBJECT_CLASS_TYPE (object_class),
+					  G_SIGNAL_RUN_FIRST,
+					  G_STRUCT_OFFSET (NMItemProviderClass, item_changed),
+					  NULL, NULL,
+					  g_cclosure_marshal_VOID__OBJECT,
+					  G_TYPE_NONE, 1,
+					  NM_TYPE_LIST_ITEM);
+
+    signals[ITEM_REMOVED] =
+		g_signal_new ("item-removed",
+					  G_OBJECT_CLASS_TYPE (object_class),
+					  G_SIGNAL_RUN_FIRST,
+					  G_STRUCT_OFFSET (NMItemProviderClass, item_removed),
+					  NULL, NULL,
+					  g_cclosure_marshal_VOID__OBJECT,
+					  G_TYPE_NONE, 1,
+					  NM_TYPE_LIST_ITEM);
+}
diff --git a/libnm-gtk/nm-item-provider.h b/libnm-gtk/nm-item-provider.h
new file mode 100644
index 0000000..6376375
--- /dev/null
+++ b/libnm-gtk/nm-item-provider.h
@@ -0,0 +1,79 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2009 Novell, Inc.
+ */
+
+#ifndef NM_ITEM_PROVIDER_H
+#define NM_ITEM_PROVIDER_H
+
+#include <glib-object.h>
+#include <nm-client.h>
+#include <nm-settings-interface.h>
+#include <nm-list-item.h>
+
+G_BEGIN_DECLS
+
+#define NM_TYPE_ITEM_PROVIDER            (nm_item_provider_get_type ())
+#define NM_ITEM_PROVIDER(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_ITEM_PROVIDER, NMItemProvider))
+#define NM_ITEM_PROVIDER_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_ITEM_PROVIDER, NMItemProviderClass))
+#define NM_IS_ITEM_PROVIDER(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_ITEM_PROVIDER))
+#define NM_IS_ITEM_PROVIDER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NM_TYPE_ITEM_PROVIDER))
+#define NM_ITEM_PROVIDER_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_ITEM_PROVIDER, NMItemProviderClass))
+
+#define NM_ITEM_PROVIDER_CLIENT "client"
+
+typedef struct {
+    GObject parent;
+} NMItemProvider;
+
+typedef struct {
+    GObjectClass parent_class;
+
+    /* Methods */
+    void (*connection_added) (NMItemProvider *self,
+                              NMSettingsConnectionInterface *connection);
+
+    /* Signals */
+    void (*item_added) (NMItemProvider *self,
+                        NMListItem *item);
+
+    void (*item_changed) (NMItemProvider *self,
+                          NMListItem *item);
+
+    void (*item_removed) (NMItemProvider *self,
+                          NMListItem *item);
+} NMItemProviderClass;
+
+GType nm_item_provider_get_type (void);
+
+void      nm_item_provider_add_settings (NMItemProvider *self,
+                                         NMSettingsInterface *settings);
+
+NMClient *nm_item_provider_get_client   (NMItemProvider *self);
+GSList   *nm_item_provider_get_connections (NMItemProvider *self);
+
+GSList   *nm_item_provider_get_items    (NMItemProvider *self);
+
+void      nm_item_provider_item_added   (NMItemProvider *provider,
+                                         NMListItem *item);
+
+void      nm_item_provider_clear        (NMItemProvider *self);
+void      nm_item_provider_reset        (NMItemProvider *self);
+
+G_END_DECLS
+
+#endif /* NM_ITEM_PROVIDER_H */
diff --git a/libnm-gtk/nm-list-item.c b/libnm-gtk/nm-list-item.c
new file mode 100644
index 0000000..d29da51
--- /dev/null
+++ b/libnm-gtk/nm-list-item.c
@@ -0,0 +1,343 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2009 Novell, Inc.
+ */
+
+#include "nm-list-item.h"
+
+G_DEFINE_TYPE (NMListItem, nm_list_item, G_TYPE_INITIALLY_UNOWNED)
+
+enum {
+    PROP_0,
+    PROP_NAME,
+    PROP_TYPE_NAME,
+    PROP_ICON,
+    PROP_SECURITY,
+    PROP_STATUS,
+    PROP_SHOW_DELETE,
+
+    LAST_PROP
+};
+
+enum {
+	REQUEST_REMOVE,
+
+	LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+#define GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), NM_TYPE_LIST_ITEM, NMListItemPrivate))
+
+typedef struct {
+    char *name;
+    char *type_name;
+    char *security;
+    char *icon;
+    NMListItemStatus status;
+    gboolean show_delete;
+
+    gboolean disposed;
+} NMListItemPrivate;
+
+const char *
+nm_list_item_get_name (NMListItem *self)
+{
+    g_return_val_if_fail (NM_IS_LIST_ITEM (self), NULL);
+
+    return GET_PRIVATE (self)->name;
+}
+
+const char *
+nm_list_item_get_type_name (NMListItem *self)
+{
+    g_return_val_if_fail (NM_IS_LIST_ITEM (self), NULL);
+
+    return GET_PRIVATE (self)->type_name;
+}
+
+const char *
+nm_list_item_get_icon (NMListItem *self)
+{
+    g_return_val_if_fail (NM_IS_LIST_ITEM (self), NULL);
+
+    return GET_PRIVATE (self)->icon;
+}
+
+const char *
+nm_list_item_get_security (NMListItem *self)
+{
+    g_return_val_if_fail (NM_IS_LIST_ITEM (self), NULL);
+
+    return GET_PRIVATE (self)->security;
+}
+
+NMListItemStatus
+nm_list_item_get_status (NMListItem *self)
+{
+    g_return_val_if_fail (NM_IS_LIST_ITEM (self), NM_LIST_ITEM_STATUS_DISCONNECTED);
+
+    return GET_PRIVATE (self)->status;
+}
+
+gboolean
+nm_list_item_get_show_delete (NMListItem *self)
+{
+    g_return_val_if_fail (NM_IS_LIST_ITEM (self), FALSE);
+
+    return GET_PRIVATE (self)->show_delete;
+}
+
+void
+nm_list_item_request_remove (NMListItem *self)
+{
+    g_return_if_fail (NM_IS_LIST_ITEM (self));
+
+    g_signal_emit (self, signals[REQUEST_REMOVE], 0);
+}
+
+void
+nm_list_item_connect (NMListItem *self)
+{
+    g_return_if_fail (NM_IS_LIST_ITEM (self));
+
+    if (NM_LIST_ITEM_GET_CLASS (self)->connect)
+        NM_LIST_ITEM_GET_CLASS (self)->connect (self);
+}
+
+void
+nm_list_item_disconnect (NMListItem *self)
+{
+    g_return_if_fail (NM_IS_LIST_ITEM (self));
+
+    if (NM_LIST_ITEM_GET_CLASS (self)->disconnect)
+        NM_LIST_ITEM_GET_CLASS (self)->disconnect (self);
+}
+
+void
+nm_list_item_delete (NMListItem *self)
+{
+    g_return_if_fail (NM_IS_LIST_ITEM (self));
+
+    if (NM_LIST_ITEM_GET_CLASS (self)->delete)
+        NM_LIST_ITEM_GET_CLASS (self)->delete (self);
+}
+
+static int
+priority (NMListItem *self)
+{
+    return 0;
+}
+
+static int
+nm_list_item_get_priority (NMListItem *item)
+{
+    return NM_LIST_ITEM_GET_CLASS (item)->priority (item);
+}
+
+int
+nm_list_item_compare (NMListItem *self,
+                      NMListItem *other)
+{
+    int priority;
+    int other_priority;
+
+    g_return_val_if_fail (NM_IS_LIST_ITEM (self), 1);
+    g_return_val_if_fail (NM_IS_LIST_ITEM (other), 1);
+
+    priority = nm_list_item_get_priority (self);
+    other_priority = nm_list_item_get_priority (other);
+
+    if (priority > other_priority)
+        return -1;
+    else if (priority < other_priority)
+        return 1;
+
+    return g_strcmp0 (nm_list_item_get_name (self), nm_list_item_get_name (other));
+}
+
+/*****************************************************************************/
+
+static void
+nm_list_item_init (NMListItem *self)
+{
+}
+
+static void
+set_property (GObject *object, guint prop_id,
+              const GValue *value, GParamSpec *pspec)
+{
+    NMListItemPrivate *priv = GET_PRIVATE (object);
+
+    switch (prop_id) {
+    case PROP_NAME:
+        g_free (priv->name);
+        priv->name = g_value_dup_string (value);
+        g_object_notify (object, NM_LIST_ITEM_NAME);
+        break;
+    case PROP_TYPE_NAME:
+        g_free (priv->type_name);
+        priv->type_name = g_value_dup_string (value);
+        g_object_notify (object, NM_LIST_ITEM_TYPE_NAME);
+        break;
+    case PROP_ICON:
+        g_free (priv->icon);
+        priv->icon = g_value_dup_string (value);
+        g_object_notify (object, NM_LIST_ITEM_ICON);
+        break;
+    case PROP_SECURITY:
+        g_free (priv->security);
+        priv->security = g_value_dup_string (value);
+        g_object_notify (object, NM_LIST_ITEM_SECURITY);
+        break;
+    case PROP_STATUS:
+        priv->status = g_value_get_int (value);
+        g_object_notify (object, NM_LIST_ITEM_STATUS);
+        break;
+    case PROP_SHOW_DELETE:
+        priv->show_delete = g_value_get_boolean (value);
+        g_object_notify (object, NM_LIST_ITEM_SHOW_DELETE);
+        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)
+{
+    NMListItem *self = NM_LIST_ITEM (object);
+
+    switch (prop_id) {
+    case PROP_NAME:
+        g_value_set_string (value, nm_list_item_get_name (self));
+        break;
+    case PROP_TYPE_NAME:
+        g_value_set_string (value, nm_list_item_get_type_name (self));
+        break;
+    case PROP_ICON:
+        g_value_set_string (value, nm_list_item_get_icon (self));
+        break;
+    case PROP_SECURITY:
+        g_value_set_string (value, nm_list_item_get_security (self));
+        break;
+    case PROP_STATUS:
+        g_value_set_int (value, nm_list_item_get_status (self));
+        break;
+    case PROP_SHOW_DELETE:
+        g_value_set_boolean (value, nm_list_item_get_show_delete (self));
+        break;
+    default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+        break;
+    }
+}
+
+static void
+dispose (GObject *object)
+{
+    NMListItemPrivate *priv = GET_PRIVATE (object);
+
+    if (!priv->disposed) {
+        g_free (priv->name);
+        g_free (priv->type_name);
+        g_free (priv->icon);
+        g_free (priv->security);
+
+        priv->disposed = TRUE;
+    }
+
+    G_OBJECT_CLASS (nm_list_item_parent_class)->dispose (object);
+}
+
+static void
+nm_list_item_class_init (NMListItemClass *klass)
+{
+    GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+    g_type_class_add_private (object_class, sizeof (NMListItemPrivate));
+
+    object_class->set_property = set_property;
+    object_class->get_property = get_property;
+    object_class->dispose = dispose;
+
+    klass->priority = priority;
+
+    /* Properties */
+    g_object_class_install_property
+        (object_class, PROP_NAME,
+         g_param_spec_string (NM_LIST_ITEM_NAME,
+                              "Name",
+                              "Name",
+                              NULL,
+                              G_PARAM_READWRITE));
+
+    g_object_class_install_property
+        (object_class, PROP_TYPE_NAME,
+         g_param_spec_string (NM_LIST_ITEM_TYPE_NAME,
+                              "TypeName",
+                              "TypeName",
+                              NULL,
+                              G_PARAM_READWRITE));
+
+    g_object_class_install_property
+        (object_class, PROP_ICON,
+         g_param_spec_string (NM_LIST_ITEM_ICON,
+                              "Icon",
+                              "Icon",
+                              NULL,
+                              G_PARAM_READWRITE));
+
+    g_object_class_install_property
+        (object_class, PROP_SECURITY,
+         g_param_spec_string (NM_LIST_ITEM_SECURITY,
+                              "Security",
+                              "Security",
+                              NULL,
+                              G_PARAM_READWRITE));
+
+    g_object_class_install_property
+        (object_class, PROP_STATUS,
+         g_param_spec_int (NM_LIST_ITEM_STATUS,
+                           "Status",
+                           "Status",
+                           NM_LIST_ITEM_STATUS_DISCONNECTED,
+                           NM_LIST_ITEM_STATUS_CONNECTED,
+                           NM_LIST_ITEM_STATUS_DISCONNECTED,
+                           G_PARAM_READWRITE));
+
+    g_object_class_install_property
+        (object_class, PROP_SHOW_DELETE,
+         g_param_spec_boolean (NM_LIST_ITEM_SHOW_DELETE,
+                               "Show delete",
+                               "Show delete button",
+                               FALSE,
+                               G_PARAM_READWRITE));
+
+    /* Signals */
+    signals[REQUEST_REMOVE] =
+		g_signal_new ("request-remove",
+					  G_OBJECT_CLASS_TYPE (object_class),
+					  G_SIGNAL_RUN_FIRST,
+					  G_STRUCT_OFFSET (NMListItemClass, request_remove),
+					  NULL, NULL,
+					  g_cclosure_marshal_VOID__VOID,
+					  G_TYPE_NONE, 0);
+
+}
diff --git a/libnm-gtk/nm-list-item.h b/libnm-gtk/nm-list-item.h
new file mode 100644
index 0000000..15988d9
--- /dev/null
+++ b/libnm-gtk/nm-list-item.h
@@ -0,0 +1,93 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2009 Novell, Inc.
+ */
+
+#ifndef NM_LIST_ITEM_H
+#define NM_LIST_ITEM_H
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define NM_TYPE_LIST_ITEM            (nm_list_item_get_type ())
+#define NM_LIST_ITEM(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_LIST_ITEM, NMListItem))
+#define NM_LIST_ITEM_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_LIST_ITEM, NMListItemClass))
+#define NM_IS_LIST_ITEM(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_LIST_ITEM))
+#define NM_IS_LIST_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NM_TYPE_LIST_ITEM))
+#define NM_LIST_ITEM_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_LIST_ITEM, NMListItemClass))
+
+typedef enum {
+    NM_LIST_ITEM_STATUS_DISCONNECTED,
+    NM_LIST_ITEM_STATUS_CONNECTING,
+    NM_LIST_ITEM_STATUS_CONNECTED
+} NMListItemStatus;
+
+#define NM_LIST_ITEM_NAME        "name"
+#define NM_LIST_ITEM_TYPE_NAME   "type-name"
+#define NM_LIST_ITEM_ICON        "icon"
+#define NM_LIST_ITEM_SECURITY    "security"
+#define NM_LIST_ITEM_STATUS      "status"
+#define NM_LIST_ITEM_SHOW_DELETE "show-delete"
+
+/* Sorting priorities. These are summed and the items are sorted
+   in ascending numeric order (higher first) */
+#define NM_LIST_ITEM_PRIORITY_DEFAULT_ROUTE 1000
+#define NM_LIST_ITEM_PRIORITY_ACTIVATED     200
+#define NM_LIST_ITEM_PRIORITY_CONFIGURED    100
+#define NM_LIST_ITEM_PRIORITY_DEV_ETHERNET  99
+#define NM_LIST_ITEM_PRIORITY_DEV_WIFI      98
+#define NM_LIST_ITEM_PRIORITY_DEV_GSM       97
+#define NM_LIST_ITEM_PRIORITY_DEV_CDMA      96
+
+typedef struct {
+    GInitiallyUnowned parent;
+} NMListItem;
+
+typedef struct {
+    GInitiallyUnownedClass parent_class;
+
+    /* Methods */
+    void (*connect)    (NMListItem *self);
+    void (*disconnect) (NMListItem *self);
+    void (*delete)     (NMListItem *self);
+    int  (*priority)   (NMListItem *self);
+
+    /* Signals */
+    void (*request_remove) (NMListItem *self);
+} NMListItemClass;
+
+GType nm_list_item_get_type (void);
+
+const char       *nm_list_item_get_name        (NMListItem *self);
+const char       *nm_list_item_get_type_name   (NMListItem *self);
+const char       *nm_list_item_get_icon        (NMListItem *self);
+const char       *nm_list_item_get_security    (NMListItem *self);
+NMListItemStatus  nm_list_item_get_status      (NMListItem *self);
+gboolean          nm_list_item_get_show_delete (NMListItem *self);
+
+void              nm_list_item_request_remove  (NMListItem *self);
+
+void              nm_list_item_connect         (NMListItem *self);
+void              nm_list_item_disconnect      (NMListItem *self);
+void              nm_list_item_delete          (NMListItem *self);
+int               nm_list_item_compare         (NMListItem *self,
+                                                NMListItem *other);
+
+G_END_DECLS
+
+#endif /* NM_LIST_ITEM_H */
diff --git a/libnm-gtk/nm-list-model.c b/libnm-gtk/nm-list-model.c
new file mode 100644
index 0000000..e257392
--- /dev/null
+++ b/libnm-gtk/nm-list-model.c
@@ -0,0 +1,314 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2009 Novell, Inc.
+ */
+
+#include "nm-list-model.h"
+#include "nm-list-item.h"
+#include "nm-device-handler.h"
+
+G_DEFINE_TYPE (NMListModel, nm_list_model, GTK_TYPE_LIST_STORE)
+
+enum {
+    PROP_0,
+    PROP_CLIENT,
+
+    LAST_PROP
+};
+
+#define GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), NM_TYPE_LIST_MODEL, NMListModelPrivate))
+
+typedef struct {
+    NMClient *client;
+    GSList *settings;
+    NMDeviceHandler *device_handler;
+
+    gboolean disposed;
+} NMListModelPrivate;
+
+static GQuark quark_item_iter = 0;
+
+NMListModel *
+nm_list_model_new (NMClient *client)
+{
+    g_return_val_if_fail (NM_IS_CLIENT (client), NULL);
+
+    return (NMListModel *) g_object_new (NM_TYPE_LIST_MODEL,
+                                         NM_LIST_MODEL_CLIENT, client,
+                                         NULL);
+}
+
+void
+nm_list_model_add_settings (NMListModel *self,
+                            NMSettingsInterface *settings)
+{
+    NMListModelPrivate *priv;
+
+    g_return_if_fail (NM_IS_LIST_MODEL (self));
+    g_return_if_fail (NM_IS_SETTINGS_INTERFACE (settings));
+
+    priv = GET_PRIVATE (self);
+    priv->settings = g_slist_append (priv->settings, g_object_ref (settings));
+
+    g_slist_foreach (nm_device_handler_get_providers (priv->device_handler),
+                     (GFunc) nm_item_provider_add_settings, settings);
+}
+
+NMClient *
+nm_list_model_get_client (NMListModel *self)
+{
+    g_return_val_if_fail (NM_IS_LIST_MODEL (self), NULL);
+
+    return GET_PRIVATE (self)->client;
+}
+
+static void
+item_added (NMItemProvider *provider,
+            NMListItem *item,
+            gpointer user_data)
+{
+    GtkListStore *store = GTK_LIST_STORE (user_data);
+    GtkTreeIter *iter;
+
+    iter = g_slice_new0 (GtkTreeIter);
+    gtk_list_store_insert_with_values (store, iter, G_MAXINT,
+                                       NM_LIST_MODEL_COL_ITEM,        item,
+                                       NM_LIST_MODEL_COL_NAME,        nm_list_item_get_name (item),
+                                       NM_LIST_MODEL_COL_ICON,        nm_list_item_get_icon (item),
+                                       NM_LIST_MODEL_COL_SECURITY,    nm_list_item_get_security (item),
+                                       NM_LIST_MODEL_COL_STATUS,      nm_list_item_get_status (item),
+                                       NM_LIST_MODEL_COL_SHOW_DELETE, nm_list_item_get_show_delete (item),
+                                       -1);
+
+    g_object_set_qdata_full (G_OBJECT (item), quark_item_iter, iter, (GDestroyNotify) gtk_tree_iter_free);
+}
+
+static void
+item_changed (NMItemProvider *provider,
+              NMListItem *item,
+              gpointer user_data)
+{
+    GtkListStore *store = GTK_LIST_STORE (user_data);
+    GtkTreeIter *iter;
+
+    iter = (GtkTreeIter *) g_object_get_qdata (G_OBJECT (item), quark_item_iter);
+    if (iter)
+        gtk_list_store_set (store, iter,
+                            NM_LIST_MODEL_COL_ITEM,        item,
+                            NM_LIST_MODEL_COL_NAME,        nm_list_item_get_name (item),
+                            NM_LIST_MODEL_COL_ICON,        nm_list_item_get_icon (item),
+                            NM_LIST_MODEL_COL_SECURITY,    nm_list_item_get_security (item),
+                            NM_LIST_MODEL_COL_STATUS,      nm_list_item_get_status (item),
+                            NM_LIST_MODEL_COL_SHOW_DELETE, nm_list_item_get_show_delete (item),
+                            -1);
+}
+
+static void
+item_removed (NMItemProvider *provider,
+              NMListItem *item,
+              gpointer user_data)
+{
+    GtkListStore *store = GTK_LIST_STORE (user_data);
+    GtkTreeIter *iter;
+
+    iter = (GtkTreeIter *) g_object_get_qdata (G_OBJECT (item), quark_item_iter);
+    if (iter) {
+        gtk_list_store_remove (store, iter);
+        g_object_set_qdata (G_OBJECT (item), quark_item_iter, NULL);
+    }
+}
+
+static void
+device_provider_added (NMDeviceHandler *handler,
+                       NMItemProvider *provider,
+                       gpointer user_data)
+{
+    NMListModelPrivate *priv = GET_PRIVATE (user_data);
+    GSList *list;
+    GSList *iter;
+
+    g_signal_connect (provider, "item-added", G_CALLBACK (item_added), user_data);
+    g_signal_connect (provider, "item-changed", G_CALLBACK (item_changed), user_data);
+    g_signal_connect (provider, "item-removed", G_CALLBACK (item_removed), user_data);
+
+    list = nm_item_provider_get_items (provider);
+    for (iter = list; iter; iter = iter->next)
+        item_added (provider, (NMListItem *) iter->data, user_data);
+
+    for (iter = priv->settings; iter; iter = iter->next)
+        nm_item_provider_add_settings (provider, (NMSettingsInterface *) iter->data);
+}
+
+static void
+device_provider_removed (NMDeviceHandler *handler,
+                         NMItemProvider *provider,
+                         gpointer user_data)
+{
+    g_signal_handlers_disconnect_matched (provider, G_SIGNAL_MATCH_DATA,
+                                          0, 0, NULL, NULL, user_data);
+}
+
+static int
+sort_callback (GtkTreeModel *model,
+               GtkTreeIter *a,
+               GtkTreeIter *b,
+               gpointer user_data)
+{
+    NMListItem *item_a;
+    NMListItem *item_b;
+    int result;
+
+    gtk_tree_model_get (model, a, NM_LIST_MODEL_COL_ITEM, &item_a, -1);
+    gtk_tree_model_get (model, b, NM_LIST_MODEL_COL_ITEM, &item_b, -1);
+
+    result = nm_list_item_compare (item_a, item_b);
+
+    if (item_a)
+        g_object_unref (item_a);
+
+    if (item_b)
+        g_object_unref (item_b);
+
+    return result;
+}
+
+/*****************************************************************************/
+
+static void
+nm_list_model_init (NMListModel *self)
+{
+    GType types[NM_LIST_MODEL_N_COLUMNS];
+
+    types[NM_LIST_MODEL_COL_ITEM]        = NM_TYPE_LIST_ITEM;
+    types[NM_LIST_MODEL_COL_NAME]        = G_TYPE_STRING;
+    types[NM_LIST_MODEL_COL_ICON]        = G_TYPE_STRING;
+    types[NM_LIST_MODEL_COL_SECURITY]    = G_TYPE_STRING;
+    types[NM_LIST_MODEL_COL_STATUS]      = G_TYPE_INT;
+    types[NM_LIST_MODEL_COL_SHOW_DELETE] = G_TYPE_BOOLEAN;
+
+    gtk_list_store_set_column_types (GTK_LIST_STORE (self), NM_LIST_MODEL_N_COLUMNS, types);
+
+    gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (self),
+                                     NM_LIST_MODEL_COL_ITEM,
+                                     sort_callback,
+                                     NULL,
+                                     NULL);
+
+    gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (self), NM_LIST_MODEL_COL_ITEM, GTK_SORT_ASCENDING);
+}
+
+static void
+set_property (GObject *object, guint prop_id,
+              const GValue *value, GParamSpec *pspec)
+{
+    NMListModelPrivate *priv = GET_PRIVATE (object);
+
+    switch (prop_id) {
+    case PROP_CLIENT:
+        /* Construct only */
+        priv->client = 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)
+{
+    NMListModelPrivate *priv = GET_PRIVATE (object);
+
+    switch (prop_id) {
+    case PROP_CLIENT:
+        g_value_set_object (value, priv->client);
+        break;
+    default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+        break;
+    }
+}
+
+static void
+constructed (GObject *object)
+{
+    NMListModelPrivate *priv = GET_PRIVATE (object);
+    GSList *list;
+    GSList *iter;
+
+    if (G_OBJECT_CLASS (nm_list_model_parent_class)->constructed)
+        G_OBJECT_CLASS (nm_list_model_parent_class)->constructed (object);
+
+    priv->device_handler = nm_device_handler_new (priv->client);
+    g_signal_connect (priv->device_handler, "provider-added", G_CALLBACK (device_provider_added), object);
+    g_signal_connect (priv->device_handler, "provider-removed", G_CALLBACK (device_provider_removed), object);
+
+    list = nm_device_handler_get_providers (priv->device_handler);
+    for (iter = list; iter; iter = iter->next)
+        device_provider_added (priv->device_handler, NM_ITEM_PROVIDER (iter->data), object);
+
+    /* FIXME: create VPNProvider */
+}
+
+static void
+dispose (GObject *object)
+{
+    NMListModelPrivate *priv = GET_PRIVATE (object);
+
+    if (!priv->disposed) {
+        if (priv->device_handler)
+            g_object_unref (priv->device_handler);
+
+        if (priv->settings) {
+            g_slist_foreach (priv->settings, (GFunc) g_object_unref, NULL);
+            g_slist_free (priv->settings);
+            priv->settings = NULL;
+        }
+
+        if (priv->client)
+            g_object_unref (priv->client);
+
+        priv->disposed = TRUE;
+    }
+
+    G_OBJECT_CLASS (nm_list_model_parent_class)->dispose (object);
+}
+
+static void
+nm_list_model_class_init (NMListModelClass *klass)
+{
+    GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+    quark_item_iter = g_quark_from_static_string ("NMListModel-item-iter");
+
+    g_type_class_add_private (object_class, sizeof (NMListModelPrivate));
+
+    object_class->set_property = set_property;
+    object_class->get_property = get_property;
+    object_class->constructed = constructed;
+    object_class->dispose = dispose;
+
+    /* Properties */
+    g_object_class_install_property
+        (object_class, PROP_CLIENT,
+         g_param_spec_object (NM_LIST_MODEL_CLIENT,
+                              "NMClient",
+                              "NMClient",
+                              NM_TYPE_CLIENT,
+                              G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+}
diff --git a/libnm-gtk/nm-list-model.h b/libnm-gtk/nm-list-model.h
new file mode 100644
index 0000000..22f4683
--- /dev/null
+++ b/libnm-gtk/nm-list-model.h
@@ -0,0 +1,67 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2009 Novell, Inc.
+ */
+
+#ifndef NM_LIST_MODEL_H
+#define NM_LIST_MODEL_H
+
+#include <gtk/gtk.h>
+#include <nm-client.h>
+#include <nm-settings-interface.h>
+
+G_BEGIN_DECLS
+
+#define NM_TYPE_LIST_MODEL            (nm_list_model_get_type ())
+#define NM_LIST_MODEL(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_LIST_MODEL, NMListModel))
+#define NM_LIST_MODEL_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_LIST_MODEL, NMListModelClass))
+#define NM_IS_LIST_MODEL(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_LIST_MODEL))
+#define NM_IS_LIST_MODEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NM_TYPE_LIST_MODEL))
+#define NM_LIST_MODEL_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_LIST_MODEL, NMListModelClass))
+
+#define NM_LIST_MODEL_CLIENT "client"
+
+enum {
+    NM_LIST_MODEL_COL_ITEM,
+    NM_LIST_MODEL_COL_NAME,
+    NM_LIST_MODEL_COL_ICON,
+    NM_LIST_MODEL_COL_SECURITY,
+    NM_LIST_MODEL_COL_STATUS,
+    NM_LIST_MODEL_COL_SHOW_DELETE,
+
+    NM_LIST_MODEL_N_COLUMNS
+};
+
+typedef struct {
+    GtkListStore parent;
+} NMListModel;
+
+typedef struct {
+    GtkListStoreClass parent_class;
+} NMListModelClass;
+
+GType nm_list_model_get_type (void);
+
+NMListModel *nm_list_model_new          (NMClient *client);
+void         nm_list_model_add_settings (NMListModel *self,
+                                         NMSettingsInterface *settings);
+
+NMClient    *nm_list_model_get_client   (NMListModel *self);
+
+G_END_DECLS
+
+#endif /* NM_LIST_MODEL_H */
diff --git a/libnm-gtk/nm-status-icon.c b/libnm-gtk/nm-status-icon.c
new file mode 100644
index 0000000..3385624
--- /dev/null
+++ b/libnm-gtk/nm-status-icon.c
@@ -0,0 +1,244 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2009 Novell, Inc.
+ */
+
+#include "nm-status-icon.h"
+#include "nm-list-item.h"
+#include "nm-device-item.h"
+#include "nm-icon-cache.h"
+
+#define ACTIVATION_STEPS 6
+
+G_DEFINE_TYPE (NMStatusIcon, nm_status_icon, GTK_TYPE_STATUS_ICON)
+
+enum {
+    PROP_0,
+    PROP_MODEL,
+
+    LAST_PROP
+};
+
+#define GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), NM_TYPE_STATUS_ICON, NMStatusIconPrivate))
+
+typedef struct {
+    NMStatusModel *model;
+    NMListItem *item;
+
+    guint animation_id;
+    guint animation_step;
+
+    gboolean disposed;
+} NMStatusIconPrivate;
+
+GtkStatusIcon *
+nm_status_icon_new (NMStatusModel *model)
+{
+    g_return_val_if_fail (NM_IS_STATUS_MODEL (model), NULL);
+
+    return (GtkStatusIcon *) g_object_new (NM_TYPE_STATUS_ICON,
+                                           NM_STATUS_ICON_MODEL, model,
+                                           NULL);
+}
+
+static gboolean
+activation_animation (gpointer data)
+{
+    NMStatusIconPrivate *priv = GET_PRIVATE (data);
+    char *image;
+    GdkPixbuf *pixbuf;
+    int stage;
+
+    if (++priv->animation_step > ACTIVATION_STEPS)
+        priv->animation_step = 1;
+
+    if (NM_IS_DEVICE_ITEM (priv->item)) {
+        NMDeviceState state;
+        
+        state = nm_device_get_state (nm_device_item_get_device (NM_DEVICE_ITEM (priv->item)));
+        switch (state) {
+        case NM_DEVICE_STATE_PREPARE:
+            stage = 1;
+            break;
+        case NM_DEVICE_STATE_CONFIG:
+        case NM_DEVICE_STATE_NEED_AUTH:
+            stage = 2;
+            break;
+        case NM_DEVICE_STATE_IP_CONFIG:
+            stage = 3;
+            break;
+        default:
+            stage = 1;
+            break;
+        }
+    } else
+        stage = 1;
+
+    image = g_strdup_printf ("nm-stage%02d-connecting%04d", stage, priv->animation_step);
+    pixbuf = nm_icon_cache_get (image);
+    g_free (image);
+
+    if (pixbuf)
+        gtk_status_icon_set_from_pixbuf (GTK_STATUS_ICON (data), pixbuf);
+
+    return TRUE;
+}
+
+static void
+item_status_changed (NMListItem *item,
+                     GParamSpec *spec,
+                     gpointer user_data)
+{
+    NMStatusIconPrivate *priv = GET_PRIVATE (user_data);
+    GdkPixbuf *pixbuf;
+
+    if (priv->animation_id) {
+        g_source_remove (priv->animation_id);
+        priv->animation_id = 0;
+    }
+
+    switch (nm_list_item_get_status (item)) {
+    case NM_LIST_ITEM_STATUS_CONNECTING:
+        priv->animation_id = g_timeout_add (200, activation_animation, user_data);
+        activation_animation (user_data);
+        pixbuf = NULL;
+        break;
+    default:
+        pixbuf = nm_icon_cache_get (nm_list_item_get_icon (item));
+    }
+
+    if (pixbuf)
+        gtk_status_icon_set_from_pixbuf (GTK_STATUS_ICON (user_data), pixbuf);
+}
+
+static void
+model_changed (NMStatusModel *model,
+               NMListItem *active_item,
+               gpointer user_data)
+{
+    NMStatusIcon *self = NM_STATUS_ICON (user_data);
+    NMStatusIconPrivate *priv = GET_PRIVATE (self);
+
+    if (active_item == priv->item)
+        return;
+
+    g_signal_handlers_disconnect_by_func (priv->item, item_status_changed, self);
+    priv->item = active_item;
+
+    if (active_item) {
+        g_signal_connect (active_item, "notify::" NM_LIST_ITEM_STATUS, G_CALLBACK (item_status_changed), self);
+        g_signal_connect (active_item, "notify::" NM_LIST_ITEM_ICON, G_CALLBACK (item_status_changed), self);
+        item_status_changed (active_item, NULL, self);
+    } else {
+        GdkPixbuf *pixbuf;
+
+        pixbuf = nm_icon_cache_get ("nm-no-connection");
+        if (pixbuf)
+            gtk_status_icon_set_from_pixbuf (GTK_STATUS_ICON (self), pixbuf);
+    }
+}
+
+/*****************************************************************************/
+
+static void
+nm_status_icon_init (NMStatusIcon *self)
+{
+}
+
+static void
+set_property (GObject *object, guint prop_id,
+              const GValue *value, GParamSpec *pspec)
+{
+    NMStatusIconPrivate *priv = GET_PRIVATE (object);
+
+    switch (prop_id) {
+    case PROP_MODEL:
+        /* Construct only */
+        priv->model = 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)
+{
+    NMStatusIconPrivate *priv = GET_PRIVATE (object);
+
+    switch (prop_id) {
+    case PROP_MODEL:
+        g_value_set_object (value, priv->model);
+        break;
+    default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+        break;
+    }
+}
+
+static void
+constructed (GObject *object)
+{
+    NMStatusIconPrivate *priv = GET_PRIVATE (object);
+
+    if (G_OBJECT_CLASS (nm_status_icon_parent_class)->constructed)
+        G_OBJECT_CLASS (nm_status_icon_parent_class)->constructed (object);
+
+    g_signal_connect (priv->model, "changed", G_CALLBACK (model_changed), object);
+}
+
+static void
+dispose (GObject *object)
+{
+    NMStatusIconPrivate *priv = GET_PRIVATE (object);
+
+    if (!priv->disposed) {
+        if (priv->animation_id)
+            g_source_remove (priv->animation_id);
+
+        if (priv->model)
+            g_object_unref (priv->model);
+
+        priv->disposed = TRUE;
+    }
+
+    G_OBJECT_CLASS (nm_status_icon_parent_class)->dispose (object);
+}
+
+static void
+nm_status_icon_class_init (NMStatusIconClass *klass)
+{
+    GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+    g_type_class_add_private (object_class, sizeof (NMStatusIconPrivate));
+
+    object_class->set_property = set_property;
+    object_class->get_property = get_property;
+    object_class->constructed = constructed;
+    object_class->dispose = dispose;
+
+    /* Properties */
+    g_object_class_install_property
+        (object_class, PROP_MODEL,
+         g_param_spec_object (NM_STATUS_ICON_MODEL,
+                              "NMStatusModel",
+                              "NMStatusModel",
+                              NM_TYPE_STATUS_MODEL,
+                              G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+}
diff --git a/libnm-gtk/nm-status-icon.h b/libnm-gtk/nm-status-icon.h
new file mode 100644
index 0000000..7dbc123
--- /dev/null
+++ b/libnm-gtk/nm-status-icon.h
@@ -0,0 +1,51 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2009 Novell, Inc.
+ */
+
+#ifndef NM_STATUS_ICON_H
+#define NM_STATUS_ICON_H
+
+#include <gtk/gtk.h>
+#include <nm-status-model.h>
+
+G_BEGIN_DECLS
+
+#define NM_TYPE_STATUS_ICON            (nm_status_icon_get_type ())
+#define NM_STATUS_ICON(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_STATUS_ICON, NMStatusIcon))
+#define NM_STATUS_ICON_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_STATUS_ICON, NMStatusIconClass))
+#define NM_IS_STATUS_ICON(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_STATUS_ICON))
+#define NM_IS_STATUS_ICON_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NM_TYPE_STATUS_ICON))
+#define NM_STATUS_ICON_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_STATUS_ICON, NMStatusIconClass))
+
+#define NM_STATUS_ICON_MODEL "model"
+
+typedef struct {
+    GtkStatusIcon parent;
+} NMStatusIcon;
+
+typedef struct {
+    GtkStatusIconClass parent;
+} NMStatusIconClass;
+
+GType nm_status_icon_get_type (void);
+
+GtkStatusIcon *nm_status_icon_new (NMStatusModel *model);
+
+G_END_DECLS
+
+#endif /* NM_STATUS_ICON_H */
diff --git a/libnm-gtk/nm-status-model.c b/libnm-gtk/nm-status-model.c
new file mode 100644
index 0000000..a0f482f
--- /dev/null
+++ b/libnm-gtk/nm-status-model.c
@@ -0,0 +1,126 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2009 Novell, Inc.
+ */
+
+#include "nm-status-model.h"
+
+G_DEFINE_TYPE (NMStatusModel, nm_status_model, GTK_TYPE_TREE_MODEL_FILTER)
+
+enum {
+    CHANGED,
+
+    LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+GtkTreeModel *
+nm_status_model_new (GtkTreeModel *list_model)
+{
+    g_return_val_if_fail (GTK_IS_TREE_MODEL (list_model), NULL);
+
+    return (GtkTreeModel *) g_object_new (NM_TYPE_STATUS_MODEL,
+                                          "child-model", list_model,
+                                          NULL);
+}
+
+NMListItem *
+nm_status_model_get_active_item (NMStatusModel *self)
+{
+    NMListItem *item = NULL;
+    GtkTreeIter iter;
+
+    g_return_val_if_fail (NM_IS_STATUS_MODEL (self), NULL);
+
+    if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (self), &iter))
+        gtk_tree_model_get (GTK_TREE_MODEL (self), &iter, NM_LIST_MODEL_COL_ITEM, &item, -1);
+
+    return item;
+}
+
+static void
+model_changed (NMStatusModel *self)
+{
+    NMListItem *item;
+
+    item = nm_status_model_get_active_item (self);
+    g_signal_emit (self, signals[CHANGED], 0, item);
+    g_object_unref (item);
+}
+
+static gboolean
+row_visible_func (GtkTreeModel *model,
+                  GtkTreeIter  *iter,
+                  gpointer      data)
+{
+    NMListItem *item = NULL;
+    gboolean visible = FALSE;
+
+    gtk_tree_model_get (model, iter, NM_LIST_MODEL_COL_ITEM, &item, -1);
+    if (item) {
+        NMListItemStatus status;
+
+        status = nm_list_item_get_status (item);
+        g_object_unref (item);
+
+        if (status == NM_LIST_ITEM_STATUS_CONNECTED || status == NM_LIST_ITEM_STATUS_CONNECTING)
+            visible = TRUE;
+    }
+
+    return visible;
+}
+
+/*****************************************************************************/
+
+static void
+nm_status_model_init (NMStatusModel *self)
+{
+    gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (self),
+                                            row_visible_func, NULL, NULL);
+
+    g_signal_connect_swapped (self, "row-deleted", G_CALLBACK (model_changed), self);
+    g_signal_connect_swapped (self, "row-inserted", G_CALLBACK (model_changed), self);
+    g_signal_connect_swapped (self, "rows-reordered", G_CALLBACK (model_changed), self);
+}
+
+static void
+finalize (GObject *object)
+{
+    g_signal_handlers_disconnect_by_func (object, model_changed, object);
+
+    G_OBJECT_CLASS (nm_status_model_parent_class)->finalize (object);
+}
+
+static void
+nm_status_model_class_init (NMStatusModelClass *klass)
+{
+    GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+    object_class->finalize = finalize;
+
+    /* Signals */
+    signals[CHANGED] =
+		g_signal_new ("changed",
+					  G_OBJECT_CLASS_TYPE (object_class),
+					  G_SIGNAL_RUN_FIRST,
+					  G_STRUCT_OFFSET (NMStatusModelClass, changed),
+					  NULL, NULL,
+					  g_cclosure_marshal_VOID__OBJECT,
+					  G_TYPE_NONE, 1,
+                      NM_TYPE_LIST_ITEM);
+}
diff --git a/libnm-gtk/nm-status-model.h b/libnm-gtk/nm-status-model.h
new file mode 100644
index 0000000..38aed54
--- /dev/null
+++ b/libnm-gtk/nm-status-model.h
@@ -0,0 +1,55 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2009 Novell, Inc.
+ */
+
+#ifndef NM_STATUS_MODEL_H
+#define NM_STATUS_MODEL_H
+
+#include <gtk/gtk.h>
+#include <nm-list-model.h>
+#include <nm-list-item.h>
+
+G_BEGIN_DECLS
+
+#define NM_TYPE_STATUS_MODEL            (nm_status_model_get_type ())
+#define NM_STATUS_MODEL(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_STATUS_MODEL, NMStatusModel))
+#define NM_STATUS_MODEL_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_STATUS_MODEL, NMStatusModelClass))
+#define NM_IS_STATUS_MODEL(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_STATUS_MODEL))
+#define NM_IS_STATUS_MODEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NM_TYPE_STATUS_MODEL))
+#define NM_STATUS_MODEL_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_STATUS_MODEL, NMStatusModelClass))
+
+typedef struct {
+    GtkTreeModelFilter parent;
+} NMStatusModel;
+
+typedef struct {
+    GtkTreeModelFilterClass parent_class;
+
+    /* Signals */
+    void (*changed) (NMStatusModel *self,
+                     NMListItem *active_item);
+} NMStatusModelClass;
+
+GType nm_status_model_get_type (void);
+
+GtkTreeModel *nm_status_model_new             (GtkTreeModel *list_model);
+NMListItem   *nm_status_model_get_active_item (NMStatusModel *self);
+
+G_END_DECLS
+
+#endif /* NM_STATUS_MODEL_H */
diff --git a/libnm-gtk/nm-wifi-item.c b/libnm-gtk/nm-wifi-item.c
new file mode 100644
index 0000000..1d6a780
--- /dev/null
+++ b/libnm-gtk/nm-wifi-item.c
@@ -0,0 +1,592 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2009 Novell, Inc.
+ */
+
+#include <glib/gi18n.h>
+#include <nm-setting-connection.h>
+#include <nm-setting-wireless.h>
+#include <nm-setting-wireless-security.h>
+#include <nm-setting-8021x.h>
+#include <nm-utils.h>
+#include "nm-wifi-item.h"
+#include "wireless-dialog.h"
+#include "nm-icon-cache.h"
+#include "utils.h"
+
+G_DEFINE_TYPE (NMWifiItem, nm_wifi_item, NM_TYPE_DEVICE_ITEM)
+
+enum {
+    PROP_0,
+    PROP_AP,
+
+    LAST_PROP
+};
+
+#define GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), NM_TYPE_WIFI_ITEM, NMWifiItemPrivate))
+
+typedef struct {
+    GSList *ap_list;
+    NMAccessPoint *current_ap;
+
+    gboolean disposed;
+} NMWifiItemPrivate;
+
+NMListItem *
+nm_wifi_item_new (NMClient *client,
+                  NMDeviceWifi *device,
+                  NMAccessPoint *ap,
+                  NMSettingsConnectionInterface *connection)
+{
+    g_return_val_if_fail (NM_IS_CLIENT (client), NULL);
+    g_return_val_if_fail (NM_IS_DEVICE_WIFI (device), NULL);
+    g_return_val_if_fail (NM_IS_ACCESS_POINT (ap), NULL);
+
+    return (NMListItem *) g_object_new (NM_TYPE_WIFI_ITEM,
+                                        NM_LIST_ITEM_TYPE_NAME, _("WiFi"),
+                                        NM_CONNECTION_ITEM_CLIENT, client,
+                                        NM_CONNECTION_ITEM_CONNECTION, connection,
+                                        NM_DEVICE_ITEM_DEVICE, device,
+                                        NM_WIFI_ITEM_AP, ap,
+                                        NULL);
+}
+
+NMAccessPoint *
+nm_wifi_item_get_ap (NMWifiItem *self)
+{
+    g_return_val_if_fail (NM_IS_WIFI_ITEM (self), NULL);
+
+    return GET_PRIVATE (self)->current_ap;
+}
+
+static void
+update_icon (NMWifiItem *self)
+{
+    NMWifiItemPrivate *priv = GET_PRIVATE (self);
+    const char *icon;
+    guint strength;
+
+    strength = CLAMP (nm_access_point_get_strength (priv->current_ap), 0, 100);
+    if (strength > 80)
+        icon = "nm-signal-100-active";
+    else if (strength > 55)
+        icon = "nm-signal-75-active";
+    else if (strength > 30)
+        icon = "nm-signal-50-active";
+    else if (strength > 5)
+        icon = "nm-signal-25-active";
+    else
+        icon = "nm-signal-00-active";
+
+    if (icon)
+        g_object_set (self, NM_LIST_ITEM_ICON, icon, NULL);
+}
+
+static void
+update_current_ap (NMWifiItem *self)
+{
+    NMWifiItemPrivate *priv = GET_PRIVATE (self);
+    GSList *iter;
+
+    /* FIXME: If device is activated, use activation AP only */
+
+    for (iter = priv->ap_list; iter; iter = iter->next) {
+        NMAccessPoint *ap = (NMAccessPoint *) iter->data;
+
+        if (!priv->current_ap || nm_access_point_get_strength (priv->current_ap) < nm_access_point_get_strength (ap))
+            priv->current_ap = ap;
+    }
+
+    update_icon (self);
+}
+
+gboolean
+nm_wifi_item_add_ap (NMWifiItem *self,
+                     NMAccessPoint *ap)
+{
+    NMWifiItemPrivate *priv;
+
+    g_return_val_if_fail (NM_IS_WIFI_ITEM (self), FALSE);
+    g_return_val_if_fail (NM_IS_ACCESS_POINT (ap), FALSE);
+
+    priv = GET_PRIVATE (self);
+    if (priv->current_ap && !utils_access_point_is_compatible (priv->current_ap, ap))
+        return FALSE;
+
+    priv->ap_list = g_slist_prepend (priv->ap_list, g_object_ref (ap));
+    update_current_ap (self);
+
+    g_signal_connect_swapped (ap, "notify::" NM_ACCESS_POINT_STRENGTH, G_CALLBACK (update_current_ap), self);
+
+    return TRUE;
+}
+
+void
+nm_wifi_item_remove_ap (NMWifiItem *self,
+                        NMAccessPoint *ap)
+{
+    NMWifiItemPrivate *priv;
+    GSList *iter;
+
+    g_return_if_fail (NM_IS_WIFI_ITEM (self));
+    g_return_if_fail (NM_IS_ACCESS_POINT (ap));
+
+    priv = GET_PRIVATE (self);
+    for (iter = priv->ap_list; iter; iter = iter->next) {
+        if (ap != iter->data)
+            continue;
+
+        g_signal_handlers_disconnect_matched (ap,
+                                              G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA,
+                                              0, 0, NULL, update_current_ap, self);
+
+        priv->ap_list = g_slist_delete_link (priv->ap_list, iter);
+        g_object_unref (ap);
+
+        if (priv->ap_list)
+            update_current_ap (self);
+        else
+            /* No APs left, die */
+            nm_list_item_request_remove (NM_LIST_ITEM (self));
+
+        break;
+    }
+}
+
+static char *
+wifi_get_specific_object (NMDeviceItem *item)
+{
+    NMAccessPoint *ap;
+
+    ap = GET_PRIVATE (item)->current_ap;
+
+    return g_strdup (nm_object_get_path (NM_OBJECT (ap)));
+}
+
+static int
+priority (NMListItem *item)
+{
+    return NM_LIST_ITEM_PRIORITY_DEV_WIFI + NM_LIST_ITEM_CLASS (nm_wifi_item_parent_class)->priority (item);
+}
+
+static const char * default_ssid_list[] = {
+    "linksys",
+    "linksys-a",
+    "linksys-g",
+    "default",
+    "belkin54g",
+    "NETGEAR",
+    NULL
+};
+
+static gboolean
+is_manufacturer_default_ssid (const GByteArray *ssid)
+{
+    const char **default_ssid = default_ssid_list;
+
+    while (*default_ssid) {
+        if (ssid->len == strlen (*default_ssid)) {
+            if (!memcmp (*default_ssid, ssid->data, ssid->len))
+                return TRUE;
+        }
+        default_ssid++;
+    }
+    return FALSE;
+}
+
+static void
+add_ciphers_from_flags (NMSettingWirelessSecurity *sec,
+                        guint32 flags,
+                        gboolean pairwise)
+{
+    if (pairwise) {
+        if (flags & NM_802_11_AP_SEC_PAIR_TKIP)
+            nm_setting_wireless_security_add_pairwise (sec, "tkip");
+        if (flags & NM_802_11_AP_SEC_PAIR_CCMP)
+            nm_setting_wireless_security_add_pairwise (sec, "ccmp");
+    } else {
+        if (flags & NM_802_11_AP_SEC_GROUP_WEP40)
+            nm_setting_wireless_security_add_group (sec, "wep40");
+        if (flags & NM_802_11_AP_SEC_GROUP_WEP104)
+            nm_setting_wireless_security_add_group (sec, "wep104");
+        if (flags & NM_802_11_AP_SEC_GROUP_TKIP)
+            nm_setting_wireless_security_add_group (sec, "tkip");
+        if (flags & NM_802_11_AP_SEC_GROUP_CCMP)
+            nm_setting_wireless_security_add_group (sec, "ccmp");
+    }
+}
+
+static NMSettingWirelessSecurity *
+get_security_for_ap (NMAccessPoint *ap,
+                     guint32 dev_caps,
+                     gboolean *supported,
+                     NMSetting8021x **s_8021x)
+{
+    NMSettingWirelessSecurity *sec;
+    NM80211Mode mode;
+    guint32 flags;
+    guint32 wpa_flags;
+    guint32 rsn_flags;
+
+    g_return_val_if_fail (NM_IS_ACCESS_POINT (ap), NULL);
+    g_return_val_if_fail (supported != NULL, NULL);
+    g_return_val_if_fail (*supported == TRUE, NULL);
+    g_return_val_if_fail (s_8021x != NULL, NULL);
+    g_return_val_if_fail (*s_8021x == NULL, NULL);
+
+    sec = (NMSettingWirelessSecurity *) nm_setting_wireless_security_new ();
+
+    mode = nm_access_point_get_mode (ap);
+    flags = nm_access_point_get_flags (ap);
+    wpa_flags = nm_access_point_get_wpa_flags (ap);
+    rsn_flags = nm_access_point_get_rsn_flags (ap);
+
+    /* No security */
+    if (   !(flags & NM_802_11_AP_FLAGS_PRIVACY)
+           && (wpa_flags == NM_802_11_AP_SEC_NONE)
+           && (rsn_flags == NM_802_11_AP_SEC_NONE))
+        goto none;
+
+    /* Static WEP, Dynamic WEP, or LEAP */
+    if (flags & NM_802_11_AP_FLAGS_PRIVACY) {
+        if ((dev_caps & NM_WIFI_DEVICE_CAP_RSN) || (dev_caps & NM_WIFI_DEVICE_CAP_WPA)) {
+            /* If the device can do WPA/RSN but the AP has no WPA/RSN informatoin
+             * elements, it must be LEAP or static/dynamic WEP.
+             */
+            if ((wpa_flags == NM_802_11_AP_SEC_NONE) && (rsn_flags == NM_802_11_AP_SEC_NONE)) {
+                g_object_set (sec,
+                              NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "none",
+                              NM_SETTING_WIRELESS_SECURITY_WEP_TX_KEYIDX, 0,
+                              NULL);
+                return sec;
+            }
+            /* Otherwise, the AP supports WPA or RSN, which is preferred */
+        } else {
+            /* Device can't do WPA/RSN, but can at least pass through the
+             * WPA/RSN information elements from a scan.  Since Privacy was
+             * advertised, LEAP or static/dynamic WEP must be in use.
+             */
+            g_object_set (sec,
+                          NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "none",
+                          NM_SETTING_WIRELESS_SECURITY_WEP_TX_KEYIDX, 0,
+                          NULL);
+            return sec;
+        }
+    }
+
+    /* Stuff after this point requires infrastructure */
+    if (mode != NM_802_11_MODE_INFRA) {
+        *supported = FALSE;
+        goto none;
+    }
+
+    /* WPA2 PSK first */
+    if (   (rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_PSK)
+           && (dev_caps & NM_WIFI_DEVICE_CAP_RSN)) {
+        g_object_set (sec, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "wpa-psk", NULL);
+        nm_setting_wireless_security_add_proto (sec, "rsn");
+        add_ciphers_from_flags (sec, rsn_flags, TRUE);
+        add_ciphers_from_flags (sec, rsn_flags, FALSE);
+        return sec;
+    }
+
+    /* WPA PSK */
+    if (   (wpa_flags & NM_802_11_AP_SEC_KEY_MGMT_PSK)
+           && (dev_caps & NM_WIFI_DEVICE_CAP_WPA)) {
+        g_object_set (sec, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "wpa-psk", NULL);
+        nm_setting_wireless_security_add_proto (sec, "wpa");
+        add_ciphers_from_flags (sec, wpa_flags, TRUE);
+        add_ciphers_from_flags (sec, wpa_flags, FALSE);
+        return sec;
+    }
+
+    /* WPA2 Enterprise */
+    if (   (rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_802_1X)
+           && (dev_caps & NM_WIFI_DEVICE_CAP_RSN)) {
+        g_object_set (sec, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "wpa-eap", NULL);
+        nm_setting_wireless_security_add_proto (sec, "rsn");
+        add_ciphers_from_flags (sec, rsn_flags, TRUE);
+        add_ciphers_from_flags (sec, rsn_flags, FALSE);
+
+        *s_8021x = NM_SETTING_802_1X (nm_setting_802_1x_new ());
+        nm_setting_802_1x_add_eap_method (*s_8021x, "ttls");
+        g_object_set (*s_8021x, NM_SETTING_802_1X_PHASE2_AUTH, "mschapv2", NULL);
+        return sec;
+    }
+
+    /* WPA Enterprise */
+    if (   (wpa_flags & NM_802_11_AP_SEC_KEY_MGMT_802_1X)
+           && (dev_caps & NM_WIFI_DEVICE_CAP_WPA)) {
+        g_object_set (sec, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "wpa-eap", NULL);
+        nm_setting_wireless_security_add_proto (sec, "wpa");
+        add_ciphers_from_flags (sec, wpa_flags, TRUE);
+        add_ciphers_from_flags (sec, wpa_flags, FALSE);
+
+        *s_8021x = NM_SETTING_802_1X (nm_setting_802_1x_new ());
+        nm_setting_802_1x_add_eap_method (*s_8021x, "ttls");
+        g_object_set (*s_8021x, NM_SETTING_802_1X_PHASE2_AUTH, "mschapv2", NULL);
+        return sec;
+    }
+
+    *supported = FALSE;
+
+ none:
+    g_object_unref (sec);
+    return NULL;
+}
+
+static NMConnection *
+create_new_connection (NMDeviceWifi *device, NMAccessPoint *ap)
+{
+    NMConnection *connection;
+    NMSettingConnection *s_con;
+    NMSettingWireless *s_wireless;
+    NMSettingWirelessSecurity *s_wireless_sec;
+    NMSetting8021x *s_8021x = NULL;
+    const GByteArray *ap_ssid;
+    char *id;
+    char buf[33];
+    int buf_len;
+    NM80211Mode mode;
+    guint32 dev_caps;
+    gboolean supported = TRUE;
+
+    dev_caps = nm_device_wifi_get_capabilities (device);
+    s_wireless_sec = get_security_for_ap (ap, dev_caps, &supported, &s_8021x);
+    if (!supported)
+        return NULL;
+
+    s_wireless = NM_SETTING_WIRELESS (nm_setting_wireless_new ());
+    ap_ssid = nm_access_point_get_ssid (ap);
+    g_object_set (s_wireless, NM_SETTING_WIRELESS_SSID, ap_ssid, NULL);
+
+    mode = nm_access_point_get_mode (ap);
+    if (mode == NM_802_11_MODE_ADHOC)
+        g_object_set (s_wireless, NM_SETTING_WIRELESS_MODE, "adhoc", NULL);
+    else if (mode == NM_802_11_MODE_INFRA)
+        g_object_set (s_wireless, NM_SETTING_WIRELESS_MODE, "infrastructure", NULL);
+    else
+        g_assert_not_reached ();
+
+    connection = nm_connection_new ();
+    nm_connection_add_setting (connection, NM_SETTING (s_wireless));
+    if (s_wireless_sec) {
+        g_object_set (s_wireless, NM_SETTING_WIRELESS_SEC, NM_SETTING_WIRELESS_SECURITY_SETTING_NAME, NULL);
+        nm_connection_add_setting (connection, NM_SETTING (s_wireless_sec));
+    }
+    if (s_8021x)
+        nm_connection_add_setting (connection, NM_SETTING (s_8021x));
+
+    s_con = NM_SETTING_CONNECTION (nm_setting_connection_new ());
+    g_object_set (s_con,
+                  NM_SETTING_CONNECTION_TYPE, nm_setting_get_name (NM_SETTING (s_wireless)),
+                  NM_SETTING_CONNECTION_AUTOCONNECT, !is_manufacturer_default_ssid (ap_ssid),
+                  NULL);
+
+    memset (buf, 0, sizeof (buf));
+    buf_len = MIN (ap_ssid->len, sizeof (buf) - 1);
+    memcpy (buf, ap_ssid->data, buf_len);
+    id = nm_utils_ssid_to_utf8 (buf, buf_len);
+    g_object_set (s_con, NM_SETTING_CONNECTION_ID, id, NULL);
+    g_free (id);
+
+    id = nm_utils_uuid_generate ();
+    g_object_set (s_con, NM_SETTING_CONNECTION_UUID, id, NULL);
+    g_free (id);
+
+    nm_connection_add_setting (connection, NM_SETTING (s_con));
+
+    return connection;
+}
+
+static void
+wireless_dialog_response_cb (NMAWirelessDialog *dialog,
+                             gint response,
+                             gpointer user_data)
+{
+    gtk_widget_hide (GTK_WIDGET (dialog));
+
+    if (response == GTK_RESPONSE_OK)
+        nm_connection_item_new_connection (NM_CONNECTION_ITEM (user_data),
+                                           nma_wireless_dialog_get_connection (dialog),
+                                           TRUE);
+
+    gtk_widget_destroy (GTK_WIDGET (dialog));
+}
+
+static void
+connect (NMListItem *item)
+{
+    NMConnection *connection;
+    NMDeviceWifi *device;
+    NMAccessPoint *ap;
+
+    connection = (NMConnection *) nm_connection_item_get_connection (NM_CONNECTION_ITEM (item));
+    if (connection) {
+        NM_LIST_ITEM_CLASS (nm_wifi_item_parent_class)->connect (item);
+        return;
+    }
+
+    /* We don't have a connection yet, so create one */
+
+    device = NM_DEVICE_WIFI (nm_device_item_get_device (NM_DEVICE_ITEM (item)));
+    ap = nm_wifi_item_get_ap (NM_WIFI_ITEM (item));
+
+    connection = create_new_connection (device, ap);
+    if (!connection)
+        return;
+
+    if (nm_connection_need_secrets (connection, NULL)) {
+        GtkWidget *dialog;
+
+        dialog = nma_wireless_dialog_new (nm_connection_item_get_client (NM_CONNECTION_ITEM (item)),
+                                          connection, NM_DEVICE (device), ap);
+        g_signal_connect (dialog, "done", G_CALLBACK (wireless_dialog_response_cb), item);
+        nma_wireless_dialog_show (NMA_WIRELESS_DIALOG (dialog));
+    } else
+        nm_connection_item_new_connection (NM_CONNECTION_ITEM (item), connection, TRUE);
+
+    g_object_unref (connection);
+}
+
+/*****************************************************************************/
+
+static void
+nm_wifi_item_init (NMWifiItem *self)
+{
+}
+
+static void
+set_property (GObject *object, guint prop_id,
+              const GValue *value, GParamSpec *pspec)
+{
+    NMWifiItem *self = NM_WIFI_ITEM (object);
+
+    switch (prop_id) {
+    case PROP_AP:
+        /* Construct only */
+        nm_wifi_item_add_ap (self, NM_ACCESS_POINT (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)
+{
+    NMWifiItemPrivate *priv = GET_PRIVATE (object);
+
+    switch (prop_id) {
+    case PROP_AP:
+        g_value_set_object (value, priv->current_ap);
+        break;
+    default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+        break;
+    }
+}
+
+static void
+constructed (GObject *object)
+{
+    NMWifiItemPrivate *priv = GET_PRIVATE (object);
+    const GByteArray *ssid;
+    char *str;
+    guint32 flags;
+	guint32 wpa_flags;
+	guint32 rsn_flags;
+
+    if (G_OBJECT_CLASS (nm_wifi_item_parent_class)->constructed)
+        G_OBJECT_CLASS (nm_wifi_item_parent_class)->constructed (object);
+
+    ssid = nm_access_point_get_ssid (priv->current_ap);
+    str = nm_utils_ssid_to_utf8 ((char *) ssid->data, ssid->len);
+    g_object_set (object, NM_LIST_ITEM_NAME, str, NULL);
+    g_free (str);
+
+	flags = nm_access_point_get_flags (priv->current_ap);
+	wpa_flags = nm_access_point_get_wpa_flags (priv->current_ap);
+	rsn_flags = nm_access_point_get_rsn_flags (priv->current_ap);
+
+    if (rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_PSK ||
+        wpa_flags & NM_802_11_AP_SEC_KEY_MGMT_PSK ||
+        rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_802_1X ||
+        wpa_flags & NM_802_11_AP_SEC_KEY_MGMT_802_1X)
+        str = "WPA encrypted";
+    else if (flags & NM_802_11_AP_FLAGS_PRIVACY)
+        str = "WEP encrypted";
+    else
+        str = NULL;
+
+    if (str)
+        g_object_set (object, NM_LIST_ITEM_SECURITY, str, NULL);
+}
+
+static void
+dispose (GObject *object)
+{
+    NMWifiItemPrivate *priv = GET_PRIVATE (object);
+
+    if (!priv->disposed) {
+        while (priv->ap_list) {
+            NMAccessPoint *ap = (NMAccessPoint *) priv->ap_list->data;
+
+            g_signal_handlers_disconnect_matched (ap,
+                                                  G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA,
+                                                  0, 0, NULL, update_current_ap, object);
+            g_object_unref (ap);
+            priv->ap_list = g_slist_delete_link (priv->ap_list, priv->ap_list);
+        }
+
+        priv->disposed = TRUE;
+    }
+
+    G_OBJECT_CLASS (nm_wifi_item_parent_class)->dispose (object);
+}
+
+
+static void
+nm_wifi_item_class_init (NMWifiItemClass *klass)
+{
+    GObjectClass *object_class = G_OBJECT_CLASS (klass);
+    NMListItemClass *list_class = NM_LIST_ITEM_CLASS (klass);
+    NMDeviceItemClass *device_class = NM_DEVICE_ITEM_CLASS (klass);
+
+    g_type_class_add_private (object_class, sizeof (NMWifiItemPrivate));
+
+    object_class->set_property = set_property;
+    object_class->get_property = get_property;
+    object_class->constructed = constructed;
+    object_class->dispose = dispose;
+
+    list_class->priority = priority;
+    list_class->connect = connect;
+
+    device_class->get_specific_object = wifi_get_specific_object;
+
+    /* Properties */
+    g_object_class_install_property
+        (object_class, PROP_AP,
+         g_param_spec_object (NM_WIFI_ITEM_AP,
+                              "NMAccessPoint",
+                              "NMAccessPoint",
+                              NM_TYPE_ACCESS_POINT,
+                              G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+}
diff --git a/libnm-gtk/nm-wifi-item.h b/libnm-gtk/nm-wifi-item.h
new file mode 100644
index 0000000..d9c0745
--- /dev/null
+++ b/libnm-gtk/nm-wifi-item.h
@@ -0,0 +1,63 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2009 Novell, Inc.
+ */
+
+#ifndef NM_WIFI_ITEM_H
+#define NM_WIFI_ITEM_H
+
+#include <glib-object.h>
+#include <nm-device-wifi.h>
+#include <nm-device-item.h>
+
+G_BEGIN_DECLS
+
+#define NM_TYPE_WIFI_ITEM            (nm_wifi_item_get_type ())
+#define NM_WIFI_ITEM(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_WIFI_ITEM, NMWifiItem))
+#define NM_WIFI_ITEM_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_WIFI_ITEM, NMWifiItemClass))
+#define NM_IS_WIFI_ITEM(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_WIFI_ITEM))
+#define NM_IS_WIFI_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NM_TYPE_WIFI_ITEM))
+#define NM_WIFI_ITEM_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_WIFI_ITEM, NMWifiItemClass))
+
+#define NM_WIFI_ITEM_AP "ap"
+
+typedef struct {
+    NMDeviceItem parent;
+} NMWifiItem;
+
+typedef struct {
+    NMDeviceItemClass parent_class;
+} NMWifiItemClass;
+
+GType nm_wifi_item_get_type (void);
+
+NMListItem *nm_wifi_item_new (NMClient *client,
+                              NMDeviceWifi *device,
+                              NMAccessPoint *ap,
+                              NMSettingsConnectionInterface *connection);
+
+NMAccessPoint *nm_wifi_item_get_ap (NMWifiItem *self);
+
+gboolean nm_wifi_item_add_ap (NMWifiItem *self,
+                              NMAccessPoint *ap);
+
+void nm_wifi_item_remove_ap (NMWifiItem *self,
+                             NMAccessPoint *ap);
+
+G_END_DECLS
+
+#endif /* NM_WIFI_ITEM_H */
diff --git a/libnm-gtk/nm-wifi-provider.c b/libnm-gtk/nm-wifi-provider.c
new file mode 100644
index 0000000..6a60704
--- /dev/null
+++ b/libnm-gtk/nm-wifi-provider.c
@@ -0,0 +1,229 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2009 Novell, Inc.
+ */
+
+#include <nm-utils.h>
+#include "nm-wifi-provider.h"
+#include "nm-wifi-item.h"
+#include "utils.h"
+
+G_DEFINE_TYPE (NMWifiProvider, nm_wifi_provider, NM_TYPE_DEVICE_PROVIDER)
+
+#define GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), NM_TYPE_WIFI_PROVIDER, NMWifiProviderPrivate))
+
+typedef struct {
+    gulong ap_added_id;
+    gulong ap_removed_id;
+
+    gboolean disposed;
+} NMWifiProviderPrivate;
+
+NMItemProvider *
+nm_wifi_provider_new (NMClient *client,
+                      NMDeviceWifi *device)
+{
+    g_return_val_if_fail (NM_IS_CLIENT (client), NULL);
+    g_return_val_if_fail (NM_IS_DEVICE_WIFI (device), NULL);
+
+    return (NMItemProvider *) g_object_new (NM_TYPE_WIFI_PROVIDER,
+                                            NM_ITEM_PROVIDER_CLIENT, client,
+                                            NM_DEVICE_PROVIDER_DEVICE, device,
+                                            NULL);
+}
+
+static void
+wifi_added (NMItemProvider *provider,
+            NMSettingsConnectionInterface *connection)
+{
+    NMDeviceProvider *device_provider = NM_DEVICE_PROVIDER (provider);
+    NMDeviceWifi *device;
+    GSList *list;
+    GSList *iter;
+    const GPtrArray *ap_list;
+    int i;
+
+    if (!nm_device_provider_ready (device_provider))
+        return;
+
+    device = NM_DEVICE_WIFI (nm_device_provider_get_device (device_provider));
+
+    /* First, see if we have an AP item already which has
+       no connection and is compatible with this connection */
+    list = nm_item_provider_get_items (provider);
+    for (iter = list; iter; iter = iter->next) {
+        NMListItem *item = (NMListItem *) iter->data;
+        NMSettingsConnectionInterface *item_connection;
+        NMAccessPoint *ap;
+
+        item_connection = nm_connection_item_get_connection (NM_CONNECTION_ITEM (item));
+        if (item_connection == connection) {
+            /* Already have this same connection why do we get called??? */
+            g_warning ("Connection already in the list, something is broken");
+            return;
+        }
+
+        if (item_connection)
+            continue;
+
+        ap = nm_wifi_item_get_ap (NM_WIFI_ITEM (item));
+        if (utils_connection_valid_for_device (NM_CONNECTION (connection), NM_DEVICE (device), ap)) {
+            g_debug ("Found connection for item %s", nm_list_item_get_name (item));
+            g_object_set (item, NM_CONNECTION_ITEM_CONNECTION, connection, NULL);
+            return;
+        }
+    }
+
+    /* That didn't work. let's see if we have a compatible AP so we can still
+       show this connection. This happens when there's multiple connections which
+       match an AP and we want to have an item for each connection */
+
+    ap_list = nm_device_wifi_get_access_points (device);
+    for (i = 0; ap_list && ap_list->len > i; i++) {
+        NMAccessPoint *ap = (NMAccessPoint *) g_ptr_array_index (ap_list, i);
+
+        if (utils_connection_valid_for_device (NM_CONNECTION (connection), NM_DEVICE (device), ap)) {
+            NMListItem *item;
+
+            g_debug ("Created new item for connection");
+            item = nm_wifi_item_new (nm_item_provider_get_client (provider), device, ap, connection);
+            nm_item_provider_item_added (provider, item);
+            break;
+        }
+    }
+}
+
+static void
+ap_added (NMDeviceWifi *device,
+          NMAccessPoint *ap,
+          gpointer user_data)
+{
+    NMItemProvider *provider = NM_ITEM_PROVIDER (user_data);
+    const GByteArray *ssid;
+    GSList *list;
+    GSList *iter;
+    NMListItem *item;
+    gboolean added = FALSE;
+
+    /* Don't add BSSs that hide their SSID */
+    ssid = nm_access_point_get_ssid (ap);
+    if (!ssid || nm_utils_is_empty_ssid (ssid->data, ssid->len))
+        return;
+
+    /* First, check if any existing item already has a compatible AP */
+    list = nm_item_provider_get_items (provider);
+    for (iter = list; iter; iter = iter->next) {
+        NMWifiItem *wifi_item = (NMWifiItem *) iter->data;
+
+        if (nm_wifi_item_add_ap (wifi_item, ap))
+            added = TRUE;
+    }
+
+    if (added)
+        return;
+
+    /* It was not compatible with any existing item, see if we
+     * have a connection for this AP */
+    list = nm_item_provider_get_connections (provider);
+    for (iter = list; iter; iter = iter->next) {
+        NMSettingsConnectionInterface *connection = (NMSettingsConnectionInterface *) iter->data;
+
+        if (!utils_connection_valid_for_device (NM_CONNECTION (connection), NM_DEVICE (device), ap))
+            continue;
+
+        item = nm_wifi_item_new (nm_item_provider_get_client (provider), device, ap, connection);
+        nm_item_provider_item_added (provider, item);
+        added = TRUE;
+    }
+
+    g_slist_free (list);
+
+    if (added)
+        return;
+
+    /* There's no connection for this AP. Create a connectionless item */
+    item = nm_wifi_item_new (nm_item_provider_get_client (provider), device, ap, NULL);
+    nm_item_provider_item_added (provider, item);
+}
+
+static void
+ap_removed (NMDeviceWifi *device,
+            NMAccessPoint *ap,
+            gpointer user_data)
+{
+    g_slist_foreach (nm_item_provider_get_items (NM_ITEM_PROVIDER (user_data)),
+                     (GFunc) nm_wifi_item_remove_ap, ap);
+}
+
+/*****************************************************************************/
+
+static void
+nm_wifi_provider_init (NMWifiProvider *self)
+{
+}
+
+static void
+constructed (GObject *object)
+{
+    NMWifiProviderPrivate *priv = GET_PRIVATE (object);
+    NMDeviceWifi *device;
+    const GPtrArray *ap_list;
+    int i;
+
+    if (G_OBJECT_CLASS (nm_wifi_provider_parent_class)->constructed)
+        G_OBJECT_CLASS (nm_wifi_provider_parent_class)->constructed (object);
+
+    device = NM_DEVICE_WIFI (nm_device_provider_get_device (NM_DEVICE_PROVIDER (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);
+
+    ap_list = nm_device_wifi_get_access_points (device);
+    for (i = 0; ap_list && ap_list->len > i; i++)
+        ap_added (device, (NMAccessPoint *) g_ptr_array_index (ap_list, i), object);
+}
+
+static void
+dispose (GObject *object)
+{
+    NMWifiProviderPrivate *priv = GET_PRIVATE (object);
+
+    if (!priv->disposed) {
+        NMDevice *device;
+
+        device = nm_device_provider_get_device (NM_DEVICE_PROVIDER (object));
+        g_signal_handler_disconnect (device, priv->ap_added_id);
+        g_signal_handler_disconnect (device, priv->ap_removed_id);
+
+        priv->disposed = TRUE;
+    }
+
+    G_OBJECT_CLASS (nm_wifi_provider_parent_class)->dispose (object);
+}
+
+static void
+nm_wifi_provider_class_init (NMWifiProviderClass *klass)
+{
+    GObjectClass *object_class = G_OBJECT_CLASS (klass);
+    NMItemProviderClass *item_class = NM_ITEM_PROVIDER_CLASS (klass);
+
+    g_type_class_add_private (object_class, sizeof (NMWifiProviderPrivate));
+
+    object_class->constructed = constructed;
+    object_class->dispose = dispose;
+
+    item_class->connection_added = wifi_added;
+}
diff --git a/libnm-gtk/nm-wifi-provider.h b/libnm-gtk/nm-wifi-provider.h
new file mode 100644
index 0000000..78d6890
--- /dev/null
+++ b/libnm-gtk/nm-wifi-provider.h
@@ -0,0 +1,51 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2009 Novell, Inc.
+ */
+
+#ifndef NM_WIFI_PROVIDER_H
+#define NM_WIFI_PROVIDER_H
+
+#include <glib-object.h>
+#include <nm-device-wifi.h>
+#include <nm-device-provider.h>
+
+G_BEGIN_DECLS
+
+#define NM_TYPE_WIFI_PROVIDER            (nm_wifi_provider_get_type ())
+#define NM_WIFI_PROVIDER(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_WIFI_PROVIDER, NMWifiProvider))
+#define NM_WIFI_PROVIDER_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_WIFI_PROVIDER, NMWifiProviderClass))
+#define NM_IS_WIFI_PROVIDER(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_WIFI_PROVIDER))
+#define NM_IS_WIFI_PROVIDER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NM_TYPE_WIFI_PROVIDER))
+#define NM_WIFI_PROVIDER_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_WIFI_PROVIDER, NMWifiProviderClass))
+
+typedef struct {
+    NMDeviceProvider parent;
+} NMWifiProvider;
+
+typedef struct {
+    NMDeviceProviderClass parent_class;
+} NMWifiProviderClass;
+
+GType nm_wifi_provider_get_type (void);
+
+NMItemProvider *nm_wifi_provider_new (NMClient *client,
+                                      NMDeviceWifi *device);
+
+G_END_DECLS
+
+#endif /* NM_WIFI_PROVIDER_H */
diff --git a/libnm-gtk/test.c b/libnm-gtk/test.c
new file mode 100644
index 0000000..1e7de4c
--- /dev/null
+++ b/libnm-gtk/test.c
@@ -0,0 +1,224 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2009 Novell, Inc.
+ */
+
+#include <gtk/gtk.h>
+#include <nm-client.h>
+#include <nm-remote-settings-system.h>
+#include "nm-list-model.h"
+#include "nm-device-model.h"
+#include "nm-status-icon.h"
+#include "nm-connection-model.h"
+#include "nm-gconf-settings.h"
+
+static void
+setup_status_icon (NMListModel *model)
+{
+    NMStatusModel *status_model;
+    GtkStatusIcon *status_icon;
+
+    status_model = NM_STATUS_MODEL (nm_status_model_new (GTK_TREE_MODEL (model)));
+    status_icon = nm_status_icon_new (status_model);
+    g_object_unref (status_model);
+}
+
+static GtkWidget *
+create_device_combo (void)
+{
+    GtkWidget *combo;
+    GtkCellRenderer *renderer;
+
+    combo = gtk_combo_box_new ();
+
+    gtk_cell_layout_clear (GTK_CELL_LAYOUT (combo));
+
+    renderer = gtk_cell_renderer_pixbuf_new ();
+    gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), renderer, TRUE);
+    gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (combo), renderer,
+                                   "pixbuf", NM_DEVICE_MODEL_COL_ICON);
+
+    renderer = gtk_cell_renderer_text_new ();
+    gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), renderer, TRUE);
+    gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (combo), renderer,
+                                   "text", NM_DEVICE_MODEL_COL_IFACE);
+
+    renderer = gtk_cell_renderer_text_new ();
+    gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), renderer, TRUE);
+    gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (combo), renderer,
+                                   "text", NM_DEVICE_MODEL_COL_DESCRIPTION);
+
+    return combo;
+}
+
+static GtkWidget *
+create_connection_tree (void)
+{
+    GtkWidget *tree;
+    GtkCellRenderer *renderer;
+    GtkTreeViewColumn *column;
+    
+    tree = gtk_tree_view_new ();
+
+    renderer = gtk_cell_renderer_text_new ();
+    column = gtk_tree_view_column_new_with_attributes ("Name",
+                                                       renderer,
+                                                       "text", NM_CONNECTION_MODEL_COL_NAME,
+                                                       NULL);
+    gtk_tree_view_append_column (GTK_TREE_VIEW (tree), column);
+
+    renderer = gtk_cell_renderer_text_new ();
+    column = gtk_tree_view_column_new_with_attributes ("Type",
+                                                       renderer,
+                                                       "text", NM_CONNECTION_MODEL_COL_TYPE,
+                                                       NULL);
+    gtk_tree_view_append_column (GTK_TREE_VIEW (tree), column);
+
+    return tree;
+}
+
+static GtkWidget *
+create_list_tree (void)
+{
+    GtkWidget *tree;
+    GtkCellRenderer *renderer;
+    GtkTreeViewColumn *column;
+    
+    tree = gtk_tree_view_new ();
+
+    renderer = gtk_cell_renderer_pixbuf_new ();
+    column = gtk_tree_view_column_new_with_attributes ("Icon",
+                                                       renderer,
+                                                       "icon-name", NM_LIST_MODEL_COL_ICON,
+                                                       NULL);
+    gtk_tree_view_append_column (GTK_TREE_VIEW (tree), column);
+
+    renderer = gtk_cell_renderer_text_new ();
+    column = gtk_tree_view_column_new_with_attributes ("Name",
+                                                       renderer,
+                                                       "text", NM_LIST_MODEL_COL_NAME,
+                                                       NULL);
+    gtk_tree_view_append_column (GTK_TREE_VIEW (tree), column);
+
+    renderer = gtk_cell_renderer_text_new ();
+    column = gtk_tree_view_column_new_with_attributes ("Security",
+                                                       renderer,
+                                                       "text", NM_LIST_MODEL_COL_SECURITY,
+                                                       NULL);
+    gtk_tree_view_append_column (GTK_TREE_VIEW (tree), column);
+
+    renderer = gtk_cell_renderer_text_new ();
+    column = gtk_tree_view_column_new_with_attributes ("Status",
+                                                       renderer,
+                                                       "text", NM_LIST_MODEL_COL_STATUS,
+                                                       NULL);
+    gtk_tree_view_append_column (GTK_TREE_VIEW (tree), column);
+
+    renderer = gtk_cell_renderer_toggle_new ();
+    column = gtk_tree_view_column_new_with_attributes ("Show delete",
+                                                       renderer,
+                                                       "active", NM_LIST_MODEL_COL_SHOW_DELETE,
+                                                       NULL);
+    gtk_tree_view_append_column (GTK_TREE_VIEW (tree), column);
+
+    return tree;
+}
+
+static void
+do_stuff (void)
+{
+    NMClient *client;
+    DBusGConnection *bus;
+    NMSettingsInterface *user_settings;
+    NMSettingsInterface *system_settings;
+    GtkTreeModel *model;
+    GtkWidget *tree;
+    GtkWidget *scrolled;
+    GtkWidget *window;
+    GtkWidget *box;
+
+    /* Window setup */
+    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+    gtk_window_set_default_size (GTK_WINDOW (window), 400, 400);
+    g_signal_connect (window, "delete-event", G_CALLBACK (gtk_main_quit), NULL);
+    box = gtk_vbox_new (FALSE, 6);
+    gtk_container_add (GTK_CONTAINER (window), box);
+
+    client = nm_client_new ();
+    bus = nm_object_get_connection (NM_OBJECT (client));
+    system_settings = (NMSettingsInterface *) nm_remote_settings_system_new (bus);
+    user_settings = (NMSettingsInterface *) nm_gconf_settings_new (bus);
+
+    /* Device model/tree */
+    model = GTK_TREE_MODEL (nm_device_model_new (client));
+    tree = create_device_combo ();
+    gtk_combo_box_set_model (GTK_COMBO_BOX (tree), model);
+    g_object_unref (model);
+    gtk_combo_box_set_active (GTK_COMBO_BOX (tree), 0);
+    gtk_box_pack_start (GTK_BOX (box), tree, FALSE, TRUE, 0);
+
+    /* Connection model/tree */
+    model = nm_connection_model_new ();
+    nm_connection_model_add_settings (NM_CONNECTION_MODEL (model), user_settings);
+    nm_connection_model_add_settings (NM_CONNECTION_MODEL (model), system_settings);
+
+    tree = create_connection_tree ();
+    gtk_tree_view_set_model (GTK_TREE_VIEW (tree), model);
+    g_object_unref (model);
+    scrolled = gtk_scrolled_window_new (NULL, NULL);
+    gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
+                                    GTK_POLICY_AUTOMATIC,
+                                    GTK_POLICY_AUTOMATIC);
+
+    gtk_container_add (GTK_CONTAINER (scrolled), tree);
+    gtk_box_pack_start (GTK_BOX (box), scrolled, TRUE, TRUE, 0);
+
+    /* List model/tree */
+    model = GTK_TREE_MODEL (nm_list_model_new (client));
+    nm_list_model_add_settings (NM_LIST_MODEL (model), user_settings);
+    nm_list_model_add_settings (NM_LIST_MODEL (model), system_settings);
+
+    tree = create_list_tree ();
+    gtk_tree_view_set_model (GTK_TREE_VIEW (tree), model);
+    setup_status_icon (NM_LIST_MODEL (model));
+    g_object_unref (model);
+
+    scrolled = gtk_scrolled_window_new (NULL, NULL);
+    gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
+                                    GTK_POLICY_AUTOMATIC,
+                                    GTK_POLICY_AUTOMATIC);
+
+    gtk_container_add (GTK_CONTAINER (scrolled), tree);
+    gtk_box_pack_start (GTK_BOX (box), scrolled, TRUE, TRUE, 0);
+
+    gtk_widget_show_all (window);
+
+    g_object_unref (user_settings);
+    g_object_unref (system_settings);
+    g_object_unref (client);
+}
+
+int
+main (int argc, char *argv[])
+{
+    gtk_init (&argc, &argv);
+
+    do_stuff ();
+    gtk_main ();
+
+    return 0;
+}
diff --git a/libnm-gtk/utils.c b/libnm-gtk/utils.c
new file mode 100644
index 0000000..80fd194
--- /dev/null
+++ b/libnm-gtk/utils.c
@@ -0,0 +1,856 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* NetworkManager Wireless Applet -- Display wireless access points and allow user control
+ *
+ * Dan Williams <dcbw redhat com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2007 Red Hat, Inc.
+ */
+
+#include <string.h>
+#include <netinet/ether.h>
+#include <glib.h>
+#include <nm-device-ethernet.h>
+#include <nm-device-wifi.h>
+#include <nm-device-bt.h>
+#include <nm-gsm-device.h>
+#include <nm-cdma-device.h>
+#include <nm-access-point.h>
+
+#include <nm-setting-connection.h>
+#include <nm-setting-wired.h>
+#include <nm-setting-wireless.h>
+#include <nm-setting-wireless-security.h>
+#include <nm-setting-8021x.h>
+#include <nm-setting-gsm.h>
+#include <nm-setting-cdma.h>
+#include <nm-setting-pppoe.h>
+#include <nm-setting-bluetooth.h>
+#include <nm-utils.h>
+
+#include "utils.h"
+
+/*
+ * utils_bin2hexstr
+ *
+ * Convert a byte-array into a hexadecimal string.
+ *
+ * Code originally by Alex Larsson <alexl redhat com> and
+ *  copyright Red Hat, Inc. under terms of the LGPL.
+ *
+ */
+char *
+utils_bin2hexstr (const char *bytes, int len, int final_len)
+{
+	static char	hex_digits[] = "0123456789abcdef";
+	char *		result;
+	int			i;
+
+	g_return_val_if_fail (bytes != NULL, NULL);
+	g_return_val_if_fail (len > 0, NULL);
+	g_return_val_if_fail (len < 256, NULL);	/* Arbitrary limit */
+
+	result = g_malloc0 (len * 2 + 1);
+	for (i = 0; i < len; i++)
+	{
+		result[2*i] = hex_digits[(bytes[i] >> 4) & 0xf];
+		result[2*i+1] = hex_digits[bytes[i] & 0xf];
+	}
+	/* Cut converted key off at the correct length for this cipher type */
+	if (final_len > -1)
+		result[final_len] = '\0';
+
+	return result;
+}
+
+static char *ignored_words[] = {
+	"Semiconductor",
+	"Components",
+	"Corporation",
+	"Communications",
+	"Company",
+	"Corp.",
+	"Corp",
+	"Co.",
+	"Inc.",
+	"Inc",
+	"Ltd.",
+	"Limited.",
+	"Intel?",
+	"chipset",
+	"adapter",
+	"[hex]",
+	"NDIS",
+	"Module",
+	NULL
+};
+
+static char *ignored_phrases[] = {
+	"Multiprotocol MAC/baseband processor",
+	"Wireless LAN Controller",
+	"Wireless LAN Adapter",
+	"Wireless Adapter",
+	"Network Connection",
+	"Wireless Cardbus Adapter",
+	"Wireless CardBus Adapter",
+	"54 Mbps Wireless PC Card",
+	"Wireless PC Card",
+	"Wireless PC",
+	"PC Card with XJACK(r) Antenna",
+	"Wireless cardbus",
+	"Wireless LAN PC Card",
+	"Technology Group Ltd.",
+	"Communication S.p.A.",
+	"Business Mobile Networks BV",
+	"Mobile Broadband Minicard Composite Device",
+	"Mobile Communications AB",
+	NULL
+};
+
+static char *
+fixup_desc_string (const char *desc)
+{
+	char *p, *temp;
+	char **words, **item;
+	GString *str;
+
+	p = temp = g_strdup (desc);
+	while (*p) {
+		if (*p == '_' || *p == ',')
+			*p = ' ';
+		p++;
+	}
+
+	/* Attempt to shorten ID by ignoring certain phrases */
+	for (item = ignored_phrases; *item; item++) {
+		guint32 ignored_len = strlen (*item);
+
+		p = strstr (temp, *item);
+		if (p)
+			memmove (p, p + ignored_len, strlen (p + ignored_len) + 1); /* +1 for the \0 */
+	}
+
+	/* Attmept to shorten ID by ignoring certain individual words */
+	words = g_strsplit (temp, " ", 0);
+	str = g_string_new_len (NULL, strlen (temp));
+	g_free (temp);
+
+	for (item = words; *item; item++) {
+		int i = 0;
+		gboolean ignore = FALSE;
+
+		if (g_ascii_isspace (**item) || (**item == '\0'))
+			continue;
+
+		while (ignored_words[i] && !ignore) {
+			if (!strcmp (*item, ignored_words[i]))
+				ignore = TRUE;
+			i++;
+		}
+
+		if (!ignore) {
+			if (str->len)
+				g_string_append_c (str, ' ');
+			g_string_append (str, *item);
+		}
+	}
+	g_strfreev (words);
+
+	temp = str->str;
+	g_string_free (str, FALSE);
+
+	return temp;
+}
+
+#define DESC_TAG "description"
+
+const char *
+utils_get_device_description (NMDevice *device)
+{
+	char *description = NULL;
+	const char *dev_product;
+	const char *dev_vendor;
+	char *product = NULL;
+	char *vendor = NULL;
+	GString *str;
+
+	g_return_val_if_fail (device != NULL, NULL);
+
+	description = g_object_get_data (G_OBJECT (device), DESC_TAG);
+	if (description)
+		return description;
+
+	dev_product = nm_device_get_product (device);
+	dev_vendor = nm_device_get_vendor (device);
+	if (!dev_product || !dev_vendor)
+		return NULL;
+
+	product = fixup_desc_string (dev_product);
+	vendor = fixup_desc_string (dev_vendor);
+
+	str = g_string_new_len (NULL, strlen (vendor) + strlen (product) + 1);
+
+	g_string_append (str, vendor);
+	g_free (vendor);
+
+	g_string_append_c (str, ' ');
+	g_string_append (str, product);
+	g_free (product);
+
+	description = str->str;
+	g_string_free (str, FALSE);
+
+	g_object_set_data_full (G_OBJECT (device),
+	                        "description", description,
+	                        (GDestroyNotify) g_free);
+
+	return description;
+}
+
+struct cf_pair {
+	guint32 chan;
+	guint32 freq;
+};
+
+static struct cf_pair a_table[] = {
+	/* A band */
+	{  7, 5035 },
+	{  8, 5040 },
+	{  9, 5045 },
+	{ 11, 5055 },
+	{ 12, 5060 },
+	{ 16, 5080 },
+	{ 34, 5170 },
+	{ 36, 5180 },
+	{ 38, 5190 },
+	{ 40, 5200 },
+	{ 42, 5210 },
+	{ 44, 5220 },
+	{ 46, 5230 },
+	{ 48, 5240 },
+	{ 50, 5250 },
+	{ 52, 5260 },
+	{ 56, 5280 },
+	{ 58, 5290 },
+	{ 60, 5300 },
+	{ 64, 5320 },
+	{ 100, 5500 },
+	{ 104, 5520 },
+	{ 108, 5540 },
+	{ 112, 5560 },
+	{ 116, 5580 },
+	{ 120, 5600 },
+	{ 124, 5620 },
+	{ 128, 5640 },
+	{ 132, 5660 },
+	{ 136, 5680 },
+	{ 140, 5700 },
+	{ 149, 5745 },
+	{ 152, 5760 },
+	{ 153, 5765 },
+	{ 157, 5785 },
+	{ 160, 5800 },
+	{ 161, 5805 },
+	{ 165, 5825 },
+	{ 183, 4915 },
+	{ 184, 4920 },
+	{ 185, 4925 },
+	{ 187, 4935 },
+	{ 188, 4945 },
+	{ 192, 4960 },
+	{ 196, 4980 },
+	{ 0, -1 }
+};
+
+static struct cf_pair bg_table[] = {
+	/* B/G band */
+	{ 1, 2412 },
+	{ 2, 2417 },
+	{ 3, 2422 },
+	{ 4, 2427 },
+	{ 5, 2432 },
+	{ 6, 2437 },
+	{ 7, 2442 },
+	{ 8, 2447 },
+	{ 9, 2452 },
+	{ 10, 2457 },
+	{ 11, 2462 },
+	{ 12, 2467 },
+	{ 13, 2472 },
+	{ 14, 2484 },
+	{ 0, -1 }
+};
+
+guint32
+utils_freq_to_channel (guint32 freq)
+{
+	int i = 0;
+
+	while (a_table[i].chan && (a_table[i].freq != freq))
+		i++;
+	if (a_table[i].chan)
+		return a_table[i].chan;
+
+	i = 0;
+	while (bg_table[i].chan && (bg_table[i].freq != freq))
+		i++;
+	return bg_table[i].chan;
+}
+
+guint32
+utils_channel_to_freq (guint32 channel, char *band)
+{
+	int i = 0;
+
+	if (!strcmp (band, "a")) {
+		while (a_table[i].chan && (a_table[i].chan != channel))
+			i++;
+		return a_table[i].freq;
+	} else if (!strcmp (band, "bg")) {
+		while (bg_table[i].chan && (bg_table[i].chan != channel))
+			i++;
+		return bg_table[i].freq;
+	}
+
+	return 0;
+}
+
+guint32
+utils_find_next_channel (guint32 channel, int direction, char *band)
+{
+	size_t a_size = sizeof (a_table) / sizeof (struct cf_pair);
+	size_t bg_size = sizeof (bg_table) / sizeof (struct cf_pair);
+	struct cf_pair *pair = NULL;
+
+	if (!strcmp (band, "a")) {
+		if (channel < a_table[0].chan)
+			return a_table[0].chan;
+		if (channel > a_table[a_size - 2].chan)
+			return a_table[a_size - 2].chan;
+		pair = &a_table[0];
+	} else if (!strcmp (band, "bg")) {
+		if (channel < bg_table[0].chan)
+			return bg_table[0].chan;
+		if (channel > bg_table[bg_size - 2].chan)
+			return bg_table[bg_size - 2].chan;
+		pair = &bg_table[0];
+	} else {
+		g_assert_not_reached ();
+		return 0;
+	}
+
+	while (pair->chan) {
+		if (channel == pair->chan)
+			return channel;
+		if ((channel < (pair+1)->chan) && (channel > pair->chan)) {
+			if (direction > 0)	
+				return (pair+1)->chan;
+			else
+				return pair->chan;
+		}
+		pair++;
+	}
+	return 0;
+}
+
+/*
+ * utils_ether_addr_valid
+ *
+ * Compares an Ethernet address against known invalid addresses.
+ *
+ */
+gboolean
+utils_ether_addr_valid (const struct ether_addr *test_addr)
+{
+	guint8 invalid_addr1[ETH_ALEN] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
+	guint8 invalid_addr2[ETH_ALEN] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+	guint8 invalid_addr3[ETH_ALEN] = {0x44, 0x44, 0x44, 0x44, 0x44, 0x44};
+	guint8 invalid_addr4[ETH_ALEN] = {0x00, 0x30, 0xb4, 0x00, 0x00, 0x00}; /* prism54 dummy MAC */
+
+	g_return_val_if_fail (test_addr != NULL, FALSE);
+
+	/* Compare the AP address the card has with invalid ethernet MAC addresses. */
+	if (!memcmp (test_addr->ether_addr_octet, &invalid_addr1, ETH_ALEN))
+		return FALSE;
+
+	if (!memcmp (test_addr->ether_addr_octet, &invalid_addr2, ETH_ALEN))
+		return FALSE;
+
+	if (!memcmp (test_addr->ether_addr_octet, &invalid_addr3, ETH_ALEN))
+		return FALSE;
+
+	if (!memcmp (test_addr->ether_addr_octet, &invalid_addr4, ETH_ALEN))
+		return FALSE;
+
+	if (test_addr->ether_addr_octet[0] & 1)			/* Multicast addresses */
+		return FALSE;
+	
+	return TRUE;
+}
+
+static gboolean
+utils_check_ap_compatible (NMAccessPoint *ap,
+                           NMConnection *connection)
+{
+	NMSettingWireless *s_wireless;
+	NMSettingWirelessSecurity *s_wireless_sec;
+	const GByteArray *setting_bssid;
+	const char *setting_mode;
+	const char *setting_band;
+	NM80211Mode ap_mode;
+	guint32 freq;
+
+	g_return_val_if_fail (NM_IS_ACCESS_POINT (ap), FALSE);
+	g_return_val_if_fail (NM_IS_CONNECTION (connection), FALSE);
+
+	s_wireless = NM_SETTING_WIRELESS (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS));
+	if (s_wireless == NULL)
+		return FALSE;
+	
+	if (!nm_utils_same_ssid (nm_setting_wireless_get_ssid (s_wireless), nm_access_point_get_ssid (ap), TRUE))
+		return FALSE;
+
+	setting_bssid = nm_setting_wireless_get_bssid (s_wireless);
+	if (setting_bssid) {
+		struct ether_addr ap_addr;
+
+		if (ether_aton_r (nm_access_point_get_hw_address (ap), &ap_addr)) {
+			if (memcmp (setting_bssid->data, &ap_addr, ETH_ALEN))
+				return FALSE;
+		}
+	}
+
+	ap_mode = nm_access_point_get_mode (ap);
+	setting_mode = nm_setting_wireless_get_mode (s_wireless);
+	if (setting_mode) {
+		if (   !strcmp (setting_mode, "infrastructure")
+		    && (ap_mode != NM_802_11_MODE_INFRA))
+			return FALSE;
+		if (   !strcmp (setting_mode, "adhoc")
+		    && (ap_mode != NM_802_11_MODE_ADHOC))
+			return FALSE;
+	}
+
+	freq = nm_access_point_get_frequency (ap);
+	setting_band = nm_setting_wireless_get_band (s_wireless);
+	if (setting_band) {
+		if (!strcmp (setting_band, "a")) {
+			if (freq < 5170 || freq > 5825)
+				return FALSE;
+		} else if (!strcmp (setting_band, "bg")) {
+			if (freq < 2412 || freq > 2472)
+				return FALSE;
+		}
+	}
+
+	// FIXME: channel check
+
+	s_wireless_sec = (NMSettingWirelessSecurity *) nm_connection_get_setting (connection,
+															    NM_TYPE_SETTING_WIRELESS_SECURITY);
+
+	return nm_setting_wireless_ap_security_compatible (s_wireless,
+											 s_wireless_sec,
+											 nm_access_point_get_flags (ap),
+											 nm_access_point_get_wpa_flags (ap),
+											 nm_access_point_get_rsn_flags (ap),
+											 nm_access_point_get_mode (ap));
+}
+
+static gboolean
+connection_valid_for_wired (NMConnection *connection,
+                            NMSettingConnection *s_con,
+                            NMDevice *device,
+                            gpointer specific_object)
+{
+	NMDeviceEthernet *ethdev = NM_DEVICE_ETHERNET (device);
+	NMSettingWired *s_wired;
+	const char *str_mac;
+	struct ether_addr *bin_mac;
+	const char *connection_type;
+	const GByteArray *setting_mac;
+	gboolean is_pppoe = FALSE;
+
+	connection_type = nm_setting_connection_get_connection_type (s_con);
+	if (!strcmp (connection_type, NM_SETTING_PPPOE_SETTING_NAME))
+		is_pppoe = TRUE;
+	
+	if (!is_pppoe && strcmp (connection_type, NM_SETTING_WIRED_SETTING_NAME))
+		return FALSE;
+
+	s_wired = NM_SETTING_WIRED (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRED));
+	if (!is_pppoe && !s_wired)
+		return FALSE;
+
+	if (s_wired) {
+		/* Match MAC address */
+		setting_mac = nm_setting_wired_get_mac_address (s_wired);
+		if (!setting_mac)
+			return TRUE;
+
+		str_mac = nm_device_ethernet_get_hw_address (ethdev);
+		g_return_val_if_fail (str_mac != NULL, FALSE);
+
+		bin_mac = ether_aton (str_mac);
+		g_return_val_if_fail (bin_mac != NULL, FALSE);
+
+		if (memcmp (bin_mac->ether_addr_octet, setting_mac->data, ETH_ALEN))
+			return FALSE;
+	}
+
+	return TRUE;
+}
+
+static gboolean
+connection_valid_for_wireless (NMConnection *connection,
+                               NMSettingConnection *s_con,
+                               NMDevice *device,
+                               gpointer specific_object)
+{
+	NMDeviceWifi *wdev = NM_DEVICE_WIFI (device);
+	NMSettingWireless *s_wireless;
+	NMSettingWirelessSecurity *s_wireless_sec;
+	const GByteArray *setting_mac;
+	const char *setting_security, *key_mgmt;
+	guint32 wcaps;
+	NMAccessPoint *ap;
+
+	if (strcmp (nm_setting_connection_get_connection_type (s_con), NM_SETTING_WIRELESS_SETTING_NAME))
+		return FALSE;
+
+	s_wireless = NM_SETTING_WIRELESS (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS));
+	g_return_val_if_fail (s_wireless != NULL, FALSE);
+
+	/* Match MAC address */
+	setting_mac = nm_setting_wireless_get_mac_address (s_wireless);
+	if (setting_mac) {
+		const char *str_mac;
+		struct ether_addr *bin_mac;
+
+		str_mac = nm_device_wifi_get_hw_address (wdev);
+		g_return_val_if_fail (str_mac != NULL, FALSE);
+
+		bin_mac = ether_aton (str_mac);
+		g_return_val_if_fail (bin_mac != NULL, FALSE);
+
+		if (memcmp (bin_mac->ether_addr_octet, setting_mac->data, ETH_ALEN))
+			return FALSE;
+	}
+
+	/* If an AP was given make sure that's compatible with the connection first */
+	if (specific_object) {
+		ap = NM_ACCESS_POINT (specific_object);
+		g_assert (ap);
+
+		if (!utils_check_ap_compatible (ap, connection))
+			return FALSE;
+	}
+
+	setting_security = nm_setting_wireless_get_security (s_wireless);
+	if (!setting_security || strcmp (setting_security, NM_SETTING_WIRELESS_SECURITY_SETTING_NAME))
+		return TRUE; /* all devices can do unencrypted networks */
+
+	s_wireless_sec = NM_SETTING_WIRELESS_SECURITY (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS_SECURITY));
+	if (!s_wireless_sec)
+		return TRUE; /* all devices can do unencrypted networks */
+
+	key_mgmt = nm_setting_wireless_security_get_key_mgmt (s_wireless_sec);
+
+	/* All devices should support static WEP */
+	if (!strcmp (key_mgmt, "none"))
+		return TRUE;
+
+	/* All devices should support legacy LEAP and Dynamic WEP */
+	if (!strcmp (key_mgmt, "ieee8021x"))
+		return TRUE;
+
+	/* Match security with device capabilities */
+	wcaps = nm_device_wifi_get_capabilities (wdev);
+
+	/* At this point, the device better have basic WPA support. */
+	if (   !(wcaps & NM_WIFI_DEVICE_CAP_WPA)
+	    || !(wcaps & NM_WIFI_DEVICE_CAP_CIPHER_TKIP))
+		return FALSE;
+
+	/* Check for only RSN */
+	if (   (nm_setting_wireless_security_get_num_protos (s_wireless_sec) == 1)
+	    && !strcmp (nm_setting_wireless_security_get_proto (s_wireless_sec, 0), "rsn")
+	    && !(wcaps & NM_WIFI_DEVICE_CAP_RSN))
+		return FALSE;
+
+	/* Check for only pairwise CCMP */
+	if (   (nm_setting_wireless_security_get_num_pairwise (s_wireless_sec) == 1)
+	    && !strcmp (nm_setting_wireless_security_get_pairwise (s_wireless_sec, 0), "ccmp")
+	    && !(wcaps & NM_WIFI_DEVICE_CAP_CIPHER_CCMP))
+		return FALSE;
+
+	/* Check for only group CCMP */
+	if (   (nm_setting_wireless_security_get_num_groups (s_wireless_sec) == 1)
+	    && !strcmp (nm_setting_wireless_security_get_group (s_wireless_sec, 0), "ccmp")
+	    && !(wcaps & NM_WIFI_DEVICE_CAP_CIPHER_CCMP))
+		return FALSE;
+
+	return TRUE;
+}
+
+static gboolean
+connection_valid_for_gsm (NMConnection *connection,
+                          NMSettingConnection *s_con,
+                          NMDevice *device,
+                          gpointer specific_object)
+{
+	NMSettingGsm *s_gsm;
+	
+	if (strcmp (nm_setting_connection_get_connection_type (s_con), NM_SETTING_GSM_SETTING_NAME))
+		return FALSE;
+
+	s_gsm = NM_SETTING_GSM (nm_connection_get_setting (connection, NM_TYPE_SETTING_GSM));
+	g_return_val_if_fail (s_gsm != NULL, FALSE);
+
+	return TRUE;
+}
+
+static gboolean
+connection_valid_for_cdma (NMConnection *connection,
+                           NMSettingConnection *s_con,
+                           NMDevice *device,
+                           gpointer specific_object)
+{
+	NMSettingCdma *s_cdma;
+	
+	if (strcmp (nm_setting_connection_get_connection_type (s_con), NM_SETTING_CDMA_SETTING_NAME))
+		return FALSE;
+
+	s_cdma = NM_SETTING_CDMA (nm_connection_get_setting (connection, NM_TYPE_SETTING_CDMA));
+	g_return_val_if_fail (s_cdma != NULL, FALSE);
+
+	return TRUE;
+}
+
+static guint32
+get_connection_bt_type (NMConnection *connection)
+{
+	NMSettingBluetooth *s_bt;
+	const char *bt_type;
+
+	s_bt = (NMSettingBluetooth *) nm_connection_get_setting (connection, NM_TYPE_SETTING_BLUETOOTH);
+	if (!s_bt)
+		return NM_BT_CAPABILITY_NONE;
+
+	bt_type = nm_setting_bluetooth_get_connection_type (s_bt);
+	g_assert (bt_type);
+
+	if (!strcmp (bt_type, NM_SETTING_BLUETOOTH_TYPE_DUN))
+		return NM_BT_CAPABILITY_DUN;
+	else if (!strcmp (bt_type, NM_SETTING_BLUETOOTH_TYPE_PANU))
+		return NM_BT_CAPABILITY_NAP;
+
+	return NM_BT_CAPABILITY_NONE;
+}
+
+static gboolean
+connection_valid_for_bt (NMConnection *connection,
+                         NMSettingConnection *s_con,
+                         NMDevice *device,
+                         gpointer specific_object)
+{
+	NMSettingBluetooth *s_bt;
+	const GByteArray *array;
+	char *str;
+	const char *hw_addr;
+	int addr_match = FALSE;
+	guint32 bt_type;
+
+	if (strcmp (nm_setting_connection_get_connection_type (s_con), NM_SETTING_BLUETOOTH_SETTING_NAME))
+		return FALSE;
+
+	s_bt = NM_SETTING_BLUETOOTH (nm_connection_get_setting (connection, NM_TYPE_SETTING_BLUETOOTH));
+	if (!s_bt)
+		return FALSE;
+
+	array = nm_setting_bluetooth_get_bdaddr (s_bt);
+	if (!array || (array->len != ETH_ALEN))
+		return FALSE;
+
+	bt_type = get_connection_bt_type (connection);
+	if (!(bt_type & nm_device_bt_get_capabilities (NM_DEVICE_BT (device))))
+		return FALSE;
+
+	str = g_strdup_printf ("%02X:%02X:%02X:%02X:%02X:%02X",
+	                       array->data[0], array->data[1], array->data[2],
+	                       array->data[3], array->data[4], array->data[5]);
+	hw_addr = nm_device_bt_get_hw_address (NM_DEVICE_BT (device));
+	if (hw_addr)
+		addr_match = !g_ascii_strcasecmp (hw_addr, str);
+	g_free (str);
+
+	return addr_match;
+}
+
+gboolean
+utils_connection_valid_for_device (NMConnection *connection,
+                                   NMDevice *device,
+                                   gpointer specific_object)
+{
+	NMSettingConnection *s_con;
+
+	g_return_val_if_fail (connection != NULL, FALSE);
+	g_return_val_if_fail (device != NULL, FALSE);
+
+	s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION));
+	g_return_val_if_fail (s_con != NULL, FALSE);
+	g_return_val_if_fail (nm_setting_connection_get_connection_type (s_con) != NULL, FALSE);
+
+	if (NM_IS_DEVICE_ETHERNET (device))
+		return connection_valid_for_wired (connection, s_con, device, specific_object);
+	else if (NM_IS_DEVICE_WIFI (device))
+		return connection_valid_for_wireless (connection, s_con, device, specific_object);
+	else if (NM_IS_GSM_DEVICE (device))
+		return connection_valid_for_gsm (connection, s_con, device, specific_object);
+	else if (NM_IS_CDMA_DEVICE (device))
+		return connection_valid_for_cdma (connection, s_con, device, specific_object);
+	else if (NM_IS_DEVICE_BT (device))
+		return connection_valid_for_bt (connection, s_con, device, specific_object);
+	else
+		g_warning ("Unknown device type '%s'", g_type_name (G_OBJECT_TYPE(device)));
+
+	return FALSE;
+}
+
+gboolean
+utils_access_point_is_compatible (NMAccessPoint *ap1,
+								  NMAccessPoint *ap2)
+{
+	const GByteArray *ssid1;
+	const GByteArray *ssid2;
+
+	if (!ap1 || !ap2)
+		return FALSE;
+
+	ssid1 = nm_access_point_get_ssid (ap1);
+	ssid2 = nm_access_point_get_ssid (ap2);
+
+	if (!ssid1 || !ssid2)
+		return FALSE;
+
+	if (ssid1->len != ssid2->len || memcmp (ssid1->data, ssid2->data, ssid1->len))
+		return FALSE;
+
+	if (nm_access_point_get_mode (ap1) != nm_access_point_get_mode (ap2) ||
+		nm_access_point_get_flags (ap1) != nm_access_point_get_flags (ap2) ||
+		nm_access_point_get_wpa_flags (ap1) != nm_access_point_get_wpa_flags (ap2) ||
+		nm_access_point_get_rsn_flags (ap1) != nm_access_point_get_rsn_flags (ap2))
+		return FALSE;
+
+	return TRUE;
+}
+
+GSList *
+utils_filter_connections_for_device (NMDevice *device, GSList *connections)
+{
+	GSList *iter;
+	GSList *filtered = NULL;
+
+	for (iter = connections; iter; iter = g_slist_next (iter)) {
+		NMConnection *connection = NM_CONNECTION (iter->data);
+
+		if (utils_connection_valid_for_device (connection, device, NULL))
+			filtered = g_slist_append (filtered, connection);
+	}
+
+	return filtered;
+}
+
+gboolean
+utils_mac_valid (const struct ether_addr *addr)
+{
+	guint8 invalid1[ETH_ALEN] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
+	guint8 invalid2[ETH_ALEN] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+	guint8 invalid3[ETH_ALEN] = {0x44, 0x44, 0x44, 0x44, 0x44, 0x44};
+	guint8 invalid4[ETH_ALEN] = {0x00, 0x30, 0xb4, 0x00, 0x00, 0x00}; /* prism54 dummy MAC */
+
+	g_return_val_if_fail (addr != NULL, FALSE);
+
+	/* Compare the AP address the card has with invalid ethernet MAC addresses. */
+	if (!memcmp (addr->ether_addr_octet, &invalid1, ETH_ALEN))
+		return FALSE;
+
+	if (!memcmp (addr->ether_addr_octet, &invalid2, ETH_ALEN))
+		return FALSE;
+
+	if (!memcmp (addr->ether_addr_octet, &invalid3, ETH_ALEN))
+		return FALSE;
+
+	if (!memcmp (addr->ether_addr_octet, &invalid4, ETH_ALEN))
+		return FALSE;
+
+	if (addr->ether_addr_octet[0] & 1) /* Multicast addresses */
+		return FALSE;
+	
+	return TRUE;
+}
+
+char *
+utils_ether_ntop (const struct ether_addr *mac)
+{
+	/* we like leading zeros and all-caps, instead
+	 * of what glibc's ether_ntop() gives us
+	 */
+	return g_strdup_printf ("%02X:%02X:%02X:%02X:%02X:%02X",
+	                        mac->ether_addr_octet[0], mac->ether_addr_octet[1],
+	                        mac->ether_addr_octet[2], mac->ether_addr_octet[3],
+	                        mac->ether_addr_octet[4], mac->ether_addr_octet[5]);
+}
+
+
+char *
+utils_next_available_name (GSList *connections, const char *format)
+{
+	GSList *names = NULL, *iter;
+	char *cname = NULL;
+	int i = 0;
+
+	for (iter = connections; iter; iter = g_slist_next (iter)) {
+		NMConnection *candidate = NM_CONNECTION (iter->data);
+		NMSettingConnection *s_con;
+		const char *id;
+
+		s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (candidate, NM_TYPE_SETTING_CONNECTION));
+		id = nm_setting_connection_get_id (s_con);
+		g_assert (id);
+		names = g_slist_append (names, (gpointer) id);
+	}	
+
+	/* Find the next available unique connection name */
+	while (!cname && (i++ < 10000)) {
+		char *temp;
+		gboolean found = FALSE;
+
+		temp = g_strdup_printf (format, i);
+		for (iter = names; iter; iter = g_slist_next (iter)) {
+			if (!strcmp (iter->data, temp)) {
+				found = TRUE;
+				break;
+			}
+		}
+		if (!found)
+			cname = temp;
+		else
+			g_free (temp);
+	}
+
+	g_slist_free (names);
+	return cname;
+}
diff --git a/libnm-gtk/utils.h b/libnm-gtk/utils.h
new file mode 100644
index 0000000..54a39f7
--- /dev/null
+++ b/libnm-gtk/utils.h
@@ -0,0 +1,57 @@
+/* NetworkManager Wireless Applet -- Display wireless access points and allow user control
+ *
+ * Dan Williams <dcbw redhat com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2007 Red Hat, Inc.
+ */
+
+#ifndef UTILS_H
+#define UTILS_H
+
+#include <glib.h>
+#include <nm-connection.h>
+#include <nm-device.h>
+#include <net/ethernet.h>
+#include <nm-access-point.h>
+
+char * utils_bin2hexstr (const char *bytes, int len, int final_len);
+
+const char *utils_get_device_description (NMDevice *device);
+
+guint32 utils_freq_to_channel (guint32 freq);
+guint32 utils_channel_to_freq (guint32 channel, char *band);
+guint32 utils_find_next_channel (guint32 channel, int direction, char *band);
+
+gboolean utils_ether_addr_valid (const struct ether_addr *test_addr);
+
+gboolean utils_connection_valid_for_device (NMConnection *connection,
+                                            NMDevice *device,
+                                            gpointer specific_object);
+
+gboolean utils_access_point_is_compatible (NMAccessPoint *ap1,
+					   NMAccessPoint *ap2);
+
+GSList *utils_filter_connections_for_device (NMDevice *device, GSList *connections);
+
+char *utils_ether_ntop (const struct ether_addr *mac);
+
+gboolean utils_mac_valid (const struct ether_addr *addr);
+
+char *utils_next_available_name (GSList *connections, const char *format);
+
+#endif /* UTILS_H */
+
diff --git a/src/wireless-dialog.c b/libnm-gtk/wireless-dialog.c
similarity index 99%
rename from src/wireless-dialog.c
rename to libnm-gtk/wireless-dialog.c
index b4e0963..6b0e96f 100644
--- a/src/wireless-dialog.c
+++ b/libnm-gtk/wireless-dialog.c
@@ -1006,8 +1006,6 @@ nma_wireless_dialog_show (NMAWirelessDialog *dialog)
 
     g_return_if_fail (NMA_IS_WIRELESS_DIALOG (dialog));
 
-    utils_hide_main_widget ();
-
     widget = GTK_WIDGET (dialog);
 
     /* Prevent focus stealing */
diff --git a/src/wireless-dialog.h b/libnm-gtk/wireless-dialog.h
similarity index 100%
rename from src/wireless-dialog.h
rename to libnm-gtk/wireless-dialog.h
diff --git a/src/wireless-helper.h b/libnm-gtk/wireless-helper.h
similarity index 100%
rename from src/wireless-helper.h
rename to libnm-gtk/wireless-helper.h
diff --git a/src/wireless-security.ui b/libnm-gtk/wireless-security.ui
similarity index 100%
rename from src/wireless-security.ui
rename to libnm-gtk/wireless-security.ui
diff --git a/src/wireless-security/Makefile.am b/libnm-gtk/wireless-security/Makefile.am
similarity index 89%
rename from src/wireless-security/Makefile.am
rename to libnm-gtk/wireless-security/Makefile.am
index 9c49a32..117d32f 100644
--- a/src/wireless-security/Makefile.am
+++ b/libnm-gtk/wireless-security/Makefile.am
@@ -30,13 +30,12 @@ libwireless_security_la_SOURCES = \
 
 libwireless_security_la_CPPFLAGS = \
 	$(NMN_CFLAGS) \
-	-I${top_srcdir}/src/gconf-helpers \
+	-I${top_srcdir}/libnm-gtk \
 	-I${top_srcdir}/src/ \
 	-DUIDIR=\""$(uidir)"\"
 
 libwireless_security_la_LIBADD = \
-	$(NMN_LIBS) \
-	${top_builddir}/src/gconf-helpers/libgconf-helpers.la
+	$(NMN_LIBS)
 
 uidir = $(datadir)/network-manager-netbook
 ui_DATA = \
diff --git a/src/wireless-security/ca-nag-dialog.ui b/libnm-gtk/wireless-security/ca-nag-dialog.ui
similarity index 100%
rename from src/wireless-security/ca-nag-dialog.ui
rename to libnm-gtk/wireless-security/ca-nag-dialog.ui
diff --git a/src/wireless-security/dynamic-wep.ui b/libnm-gtk/wireless-security/dynamic-wep.ui
similarity index 100%
rename from src/wireless-security/dynamic-wep.ui
rename to libnm-gtk/wireless-security/dynamic-wep.ui
diff --git a/src/wireless-security/eap-leap.ui b/libnm-gtk/wireless-security/eap-leap.ui
similarity index 100%
rename from src/wireless-security/eap-leap.ui
rename to libnm-gtk/wireless-security/eap-leap.ui
diff --git a/src/wireless-security/eap-method-leap.c b/libnm-gtk/wireless-security/eap-method-leap.c
similarity index 100%
rename from src/wireless-security/eap-method-leap.c
rename to libnm-gtk/wireless-security/eap-method-leap.c
diff --git a/src/wireless-security/eap-method-leap.h b/libnm-gtk/wireless-security/eap-method-leap.h
similarity index 100%
rename from src/wireless-security/eap-method-leap.h
rename to libnm-gtk/wireless-security/eap-method-leap.h
diff --git a/src/wireless-security/eap-method-peap.c b/libnm-gtk/wireless-security/eap-method-peap.c
similarity index 100%
rename from src/wireless-security/eap-method-peap.c
rename to libnm-gtk/wireless-security/eap-method-peap.c
diff --git a/src/wireless-security/eap-method-peap.h b/libnm-gtk/wireless-security/eap-method-peap.h
similarity index 100%
rename from src/wireless-security/eap-method-peap.h
rename to libnm-gtk/wireless-security/eap-method-peap.h
diff --git a/src/wireless-security/eap-method-simple.c b/libnm-gtk/wireless-security/eap-method-simple.c
similarity index 100%
rename from src/wireless-security/eap-method-simple.c
rename to libnm-gtk/wireless-security/eap-method-simple.c
diff --git a/src/wireless-security/eap-method-simple.h b/libnm-gtk/wireless-security/eap-method-simple.h
similarity index 100%
rename from src/wireless-security/eap-method-simple.h
rename to libnm-gtk/wireless-security/eap-method-simple.h
diff --git a/src/wireless-security/eap-method-tls.c b/libnm-gtk/wireless-security/eap-method-tls.c
similarity index 100%
rename from src/wireless-security/eap-method-tls.c
rename to libnm-gtk/wireless-security/eap-method-tls.c
diff --git a/src/wireless-security/eap-method-tls.h b/libnm-gtk/wireless-security/eap-method-tls.h
similarity index 100%
rename from src/wireless-security/eap-method-tls.h
rename to libnm-gtk/wireless-security/eap-method-tls.h
diff --git a/src/wireless-security/eap-method-ttls.c b/libnm-gtk/wireless-security/eap-method-ttls.c
similarity index 100%
rename from src/wireless-security/eap-method-ttls.c
rename to libnm-gtk/wireless-security/eap-method-ttls.c
diff --git a/src/wireless-security/eap-method-ttls.h b/libnm-gtk/wireless-security/eap-method-ttls.h
similarity index 100%
rename from src/wireless-security/eap-method-ttls.h
rename to libnm-gtk/wireless-security/eap-method-ttls.h
diff --git a/src/wireless-security/eap-method.c b/libnm-gtk/wireless-security/eap-method.c
similarity index 100%
rename from src/wireless-security/eap-method.c
rename to libnm-gtk/wireless-security/eap-method.c
diff --git a/src/wireless-security/eap-method.h b/libnm-gtk/wireless-security/eap-method.h
similarity index 100%
rename from src/wireless-security/eap-method.h
rename to libnm-gtk/wireless-security/eap-method.h
diff --git a/src/wireless-security/eap-peap.ui b/libnm-gtk/wireless-security/eap-peap.ui
similarity index 100%
rename from src/wireless-security/eap-peap.ui
rename to libnm-gtk/wireless-security/eap-peap.ui
diff --git a/src/wireless-security/eap-simple.ui b/libnm-gtk/wireless-security/eap-simple.ui
similarity index 100%
rename from src/wireless-security/eap-simple.ui
rename to libnm-gtk/wireless-security/eap-simple.ui
diff --git a/src/wireless-security/eap-tls.ui b/libnm-gtk/wireless-security/eap-tls.ui
similarity index 100%
rename from src/wireless-security/eap-tls.ui
rename to libnm-gtk/wireless-security/eap-tls.ui
diff --git a/src/wireless-security/eap-ttls.ui b/libnm-gtk/wireless-security/eap-ttls.ui
similarity index 100%
rename from src/wireless-security/eap-ttls.ui
rename to libnm-gtk/wireless-security/eap-ttls.ui
diff --git a/src/wireless-security/helpers.c b/libnm-gtk/wireless-security/helpers.c
similarity index 100%
rename from src/wireless-security/helpers.c
rename to libnm-gtk/wireless-security/helpers.c
diff --git a/src/wireless-security/helpers.h b/libnm-gtk/wireless-security/helpers.h
similarity index 100%
rename from src/wireless-security/helpers.h
rename to libnm-gtk/wireless-security/helpers.h
diff --git a/src/wireless-security/leap.ui b/libnm-gtk/wireless-security/leap.ui
similarity index 100%
rename from src/wireless-security/leap.ui
rename to libnm-gtk/wireless-security/leap.ui
diff --git a/src/wireless-security/wep-key.ui b/libnm-gtk/wireless-security/wep-key.ui
similarity index 100%
rename from src/wireless-security/wep-key.ui
rename to libnm-gtk/wireless-security/wep-key.ui
diff --git a/src/wireless-security/wireless-security.c b/libnm-gtk/wireless-security/wireless-security.c
similarity index 100%
rename from src/wireless-security/wireless-security.c
rename to libnm-gtk/wireless-security/wireless-security.c
diff --git a/src/wireless-security/wireless-security.h b/libnm-gtk/wireless-security/wireless-security.h
similarity index 100%
rename from src/wireless-security/wireless-security.h
rename to libnm-gtk/wireless-security/wireless-security.h
diff --git a/src/wireless-security/wpa-eap.ui b/libnm-gtk/wireless-security/wpa-eap.ui
similarity index 100%
rename from src/wireless-security/wpa-eap.ui
rename to libnm-gtk/wireless-security/wpa-eap.ui
diff --git a/src/wireless-security/wpa-psk.ui b/libnm-gtk/wireless-security/wpa-psk.ui
similarity index 100%
rename from src/wireless-security/wpa-psk.ui
rename to libnm-gtk/wireless-security/wpa-psk.ui
diff --git a/src/wireless-security/ws-dynamic-wep.c b/libnm-gtk/wireless-security/ws-dynamic-wep.c
similarity index 100%
rename from src/wireless-security/ws-dynamic-wep.c
rename to libnm-gtk/wireless-security/ws-dynamic-wep.c
diff --git a/src/wireless-security/ws-dynamic-wep.h b/libnm-gtk/wireless-security/ws-dynamic-wep.h
similarity index 100%
rename from src/wireless-security/ws-dynamic-wep.h
rename to libnm-gtk/wireless-security/ws-dynamic-wep.h
diff --git a/src/wireless-security/ws-leap.c b/libnm-gtk/wireless-security/ws-leap.c
similarity index 99%
rename from src/wireless-security/ws-leap.c
rename to libnm-gtk/wireless-security/ws-leap.c
index d2d18bb..92efffb 100644
--- a/src/wireless-security/ws-leap.c
+++ b/libnm-gtk/wireless-security/ws-leap.c
@@ -24,7 +24,6 @@
 
 #include "wireless-security.h"
 #include "utils.h"
-#include "gconf-helpers.h"
 #include "helpers.h"
 
 
diff --git a/src/wireless-security/ws-leap.h b/libnm-gtk/wireless-security/ws-leap.h
similarity index 100%
rename from src/wireless-security/ws-leap.h
rename to libnm-gtk/wireless-security/ws-leap.h
diff --git a/src/wireless-security/ws-wep-key.c b/libnm-gtk/wireless-security/ws-wep-key.c
similarity index 99%
rename from src/wireless-security/ws-wep-key.c
rename to libnm-gtk/wireless-security/ws-wep-key.c
index 21fac42..19c95cc 100644
--- a/src/wireless-security/ws-wep-key.c
+++ b/libnm-gtk/wireless-security/ws-wep-key.c
@@ -27,8 +27,6 @@
 
 #include "wireless-security.h"
 #include "utils.h"
-#include "gconf-helpers.h"
-
 
 static void
 show_toggled_cb (GtkCheckButton *button, WirelessSecurity *sec)
diff --git a/src/wireless-security/ws-wep-key.h b/libnm-gtk/wireless-security/ws-wep-key.h
similarity index 100%
rename from src/wireless-security/ws-wep-key.h
rename to libnm-gtk/wireless-security/ws-wep-key.h
diff --git a/src/wireless-security/ws-wpa-eap.c b/libnm-gtk/wireless-security/ws-wpa-eap.c
similarity index 100%
rename from src/wireless-security/ws-wpa-eap.c
rename to libnm-gtk/wireless-security/ws-wpa-eap.c
diff --git a/src/wireless-security/ws-wpa-eap.h b/libnm-gtk/wireless-security/ws-wpa-eap.h
similarity index 100%
rename from src/wireless-security/ws-wpa-eap.h
rename to libnm-gtk/wireless-security/ws-wpa-eap.h
diff --git a/src/wireless-security/ws-wpa-psk.c b/libnm-gtk/wireless-security/ws-wpa-psk.c
similarity index 99%
rename from src/wireless-security/ws-wpa-psk.c
rename to libnm-gtk/wireless-security/ws-wpa-psk.c
index 93aab61..eaa555c 100644
--- a/src/wireless-security/ws-wpa-psk.c
+++ b/libnm-gtk/wireless-security/ws-wpa-psk.c
@@ -25,7 +25,6 @@
 
 #include "wireless-security.h"
 #include "utils.h"
-#include "gconf-helpers.h"
 #include "helpers.h"
 
 #define WPA_PMK_LEN 32
diff --git a/src/wireless-security/ws-wpa-psk.h b/libnm-gtk/wireless-security/ws-wpa-psk.h
similarity index 100%
rename from src/wireless-security/ws-wpa-psk.h
rename to libnm-gtk/wireless-security/ws-wpa-psk.h
diff --git a/marshallers/.gitignore b/marshallers/.gitignore
new file mode 100644
index 0000000..5ed6c5c
--- /dev/null
+++ b/marshallers/.gitignore
@@ -0,0 +1,2 @@
+nma-marshal.[ch]
+
diff --git a/src/marshallers/Makefile.am b/marshallers/Makefile.am
similarity index 100%
rename from src/marshallers/Makefile.am
rename to marshallers/Makefile.am
diff --git a/src/marshallers/nma-marshal-main.c b/marshallers/nma-marshal-main.c
similarity index 100%
rename from src/marshallers/nma-marshal-main.c
rename to marshallers/nma-marshal-main.c
diff --git a/src/marshallers/nma-marshal.list b/marshallers/nma-marshal.list
similarity index 100%
rename from src/marshallers/nma-marshal.list
rename to marshallers/nma-marshal.list
diff --git a/po/.gitignore b/po/.gitignore
new file mode 100644
index 0000000..746eeb4
--- /dev/null
+++ b/po/.gitignore
@@ -0,0 +1,2 @@
+*.gmo
+POTFILES
diff --git a/po/POTFILES.in b/po/POTFILES.in
index b0b63d3..ad5126d 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -1,29 +1,30 @@
-src/main.c
+libnm-gtk/nm-ethernet-item.c
+libnm-gtk/nm-wifi-item.c
+libnm-gtk/nm-gsm-item.c
+libnm-gtk/nm-cdma-item.c
+libnm-gtk/wireless-dialog.c
+[type: gettext/glade]libnm-gtk/wireless-security.ui
+[type: gettext/glade]libnm-gtk/wireless-security/ca-nag-dialog.ui
+[type: gettext/glade]libnm-gtk/wireless-security/dynamic-wep.ui
+[type: gettext/glade]libnm-gtk/wireless-security/eap-leap.ui
+[type: gettext/glade]libnm-gtk/wireless-security/eap-peap.ui
+[type: gettext/glade]libnm-gtk/wireless-security/eap-simple.ui
+[type: gettext/glade]libnm-gtk/wireless-security/eap-tls.ui
+[type: gettext/glade]libnm-gtk/wireless-security/eap-ttls.ui
+[type: gettext/glade]libnm-gtk/wireless-security/leap.ui
+[type: gettext/glade]libnm-gtk/wireless-security/wep-key.ui
+[type: gettext/glade]libnm-gtk/wireless-security/wpa-eap.ui
+[type: gettext/glade]libnm-gtk/wireless-security/wpa-psk.ui
+libnm-gtk/wireless-security/eap-method-peap.c
+libnm-gtk/wireless-security/eap-method-tls.c
+libnm-gtk/wireless-security/eap-method-ttls.c
+libnm-gtk/wireless-security/eap-method.c
+libnm-gtk/wireless-security/wireless-security.c
+src/nmn-list.c
 src/nmn-applet.c
+src/main.c
+src/nmn-panel-client.c
+src/nmn-item-renderer.c
 src/nmn-connection-details.c
-src/nmn-ethernet-item.c
-src/nmn-network-item.c
-src/nmn-networks.c
-src/nmn-mobile-providers.c
 src/nmn-new-connection.c
-src/nmn-serial-item.c
-src/nmn-status-icon.c
-src/nmn-wifi-item.c
-src/wireless-dialog.c
-[type: gettext/glade]src/wireless-security.ui
-[type: gettext/glade]src/wireless-security/ca-nag-dialog.ui
-[type: gettext/glade]src/wireless-security/dynamic-wep.ui
-[type: gettext/glade]src/wireless-security/eap-leap.ui
-[type: gettext/glade]src/wireless-security/eap-peap.ui
-[type: gettext/glade]src/wireless-security/eap-simple.ui
-[type: gettext/glade]src/wireless-security/eap-tls.ui
-[type: gettext/glade]src/wireless-security/eap-ttls.ui
-[type: gettext/glade]src/wireless-security/leap.ui
-[type: gettext/glade]src/wireless-security/wep-key.ui
-[type: gettext/glade]src/wireless-security/wpa-eap.ui
-[type: gettext/glade]src/wireless-security/wpa-psk.ui
-src/wireless-security/eap-method-peap.c
-src/wireless-security/eap-method-tls.c
-src/wireless-security/eap-method-ttls.c
-src/wireless-security/eap-method.c
-src/wireless-security/wireless-security.c
+src/nmn-mobile-providers.c
diff --git a/src/.gitignore b/src/.gitignore
new file mode 100644
index 0000000..2d10d4b
--- /dev/null
+++ b/src/.gitignore
@@ -0,0 +1 @@
+network-manager-netbook
diff --git a/src/Makefile.am b/src/Makefile.am
index 25f4425..87b2edf 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,13 +1,12 @@
-SUBDIRS = marshallers gconf-helpers wireless-security
-
 NULL=
 
 libexec_PROGRAMS = network-manager-netbook
 
 network_manager_netbook_CPPFLAGS = \
 	$(NMN_CFLAGS) \
-	-I${top_srcdir}/src/gconf-helpers \
-	-I${top_srcdir}/src/wireless-security \
+	-I${top_builddir}/marshallers \
+	-I${top_srcdir}/libnm-gtk \
+	-I${top_srcdir}/libnm-gtk/wireless-security \
 	-DUIDIR=\""$(uidir)"\" \
 	-DICON_PATH=\""$(pkgdatadir)/icons/"\" \
 	-DNMNLOCALEDIR=\"$(datadir)/locale\" \
@@ -16,8 +15,9 @@ network_manager_netbook_CPPFLAGS = \
 
 network_manager_netbook_LDADD = \
 	$(NMN_LIBS) \
-	${top_builddir}/src/gconf-helpers/libgconf-helpers.la \
-	${top_builddir}/src/wireless-security/libwireless-security.la \
+	${top_builddir}/marshallers/libmarshallers.la \
+	${top_builddir}/libnm-gtk/libnm-gtk.la \
+	${top_builddir}/libnm-gtk/wireless-security/libwireless-security.la \
 	$(NULL)
 
 network_manager_netbook_SOURCES = \
@@ -25,53 +25,17 @@ network_manager_netbook_SOURCES = \
 	nmn-applet.h \
 	nmn-connection-details.c \
 	nmn-connection-details.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 \
-	nmn-icon-cache.h \
-	nmn-item.c \
-	nmn-item.h \
+	nmn-item-renderer.c \
+	nmn-item-renderer.h \
 	nmn-list.c \
 	nmn-list.h \
 	nmn-mobile-providers.c \
 	nmn-mobile-providers.h \
-	nmn-network-item.c \
-	nmn-network-item.h \
-	nmn-networks.c \
-	nmn-networks.h \
+	nmn-model.c \
+	nmn-model.h \
 	nmn-new-connection.c \
 	nmn-new-connection.h \
-	nmn-nm-data.c \
-	nmn-nm-data.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-text-item.c \
-	nmn-text-item.h \
-	nmn-wifi-handler.c \
-	nmn-wifi-handler.h \
-	nmn-wifi-item.c \
-	nmn-wifi-item.h \
-	nmn-wifi-list.c \
-	nmn-wifi-list.h \
+	nmn-panel-client.c \
+	nmn-panel-client.h \
 	main.c \
-	utils.c \
-	utils.h \
-	wireless-dialog.c \
-	wireless-dialog.h \
-	wireless-helper.h \
-	$(NULL)
-
-uidir = $(datadir)/network-manager-netbook
-ui_DATA = wireless-security.ui
-
-EXTRA_DIST = \
-	$(ui_DATA) \
 	$(NULL)
diff --git a/src/main.c b/src/main.c
index 5234a3a..67669b3 100644
--- a/src/main.c
+++ b/src/main.c
@@ -23,17 +23,31 @@
 
 #include <glib/gi18n.h>
 #include <gtk/gtk.h>
-#include <moblin-panel/mpl-panel-common.h>
-#include <moblin-panel/mpl-panel-gtk.h>
 #include "nmn-applet.h"
-#include "nmn-icon-cache.h"
-#include "utils.h"
+#include "nm-status-model.h"
+#include "nm-icon-cache.h"
+#include "nmn-panel-client.h"
+
+static void
+panel_client_show (MplPanelClient *panel_client,
+                   gpointer user_data)
+{
+    nmn_applet_show (NMN_APPLET (user_data));
+}
+
+static void
+panel_client_hide (MplPanelClient *panel_client,
+                   gpointer user_data)
+{
+    nmn_applet_hide (NMN_APPLET (user_data));
+}
 
 int
 main (int argc, char *argv[])
 {
-    MplPanelClient *panel_client;
+    NmnModel *model;
     NmnApplet *applet;
+    GtkWidget *container;
     gboolean standalone = FALSE;
     GError *error = NULL;
     GOptionEntry    entries[] = {
@@ -46,12 +60,12 @@ main (int argc, char *argv[])
 
     g_set_application_name (_("NetworkManager Netbook"));
     gtk_init_with_args (&argc, &argv, _("- NetworkManager Netbook"),
-			entries, GETTEXT_PACKAGE, &error);
+                        entries, GETTEXT_PACKAGE, &error);
 
     if (error) {
-	g_printerr ("%s\n", error->message);
-	g_error_free (error);
-	return 1;
+        g_printerr ("%s\n", error->message);
+        g_error_free (error);
+        return 1;
     }
 
     /* Force to the moblin theme */
@@ -60,31 +74,38 @@ main (int argc, char *argv[])
                                       "Moblin-Netbook",
                                       NULL);
 
+    model = nmn_model_new ();
+    applet = nmn_applet_new (model);
+
     if (standalone) {
-	GtkWidget *window;
-	window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
-	g_signal_connect (window, "delete-event", (GCallback) gtk_main_quit,
-			  NULL);
-	applet = nmn_applet_new_standalone (GTK_WINDOW (window));
-	gtk_widget_set_size_request (window, 1000, -1);
-	utils_set_main_widget (G_OBJECT (window));
-	gtk_widget_show (window);
+        container = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+        g_signal_connect (container, "delete-event", (GCallback) gtk_main_quit, NULL);
+        gtk_widget_set_size_request (container, 1000, -1);
     } else {
-	panel_client = mpl_panel_gtk_new (MPL_PANEL_NETWORK,
-					  _("network"),
-					  THEME_PATH "/network-manager-netbook.css",
-					  "unknown",
-					  TRUE);
-
-	mpl_panel_client_set_height_request (panel_client, 499);
-	applet = nmn_applet_new (panel_client);
-	utils_set_main_widget (G_OBJECT (panel_client));
+        NMStatusModel *status_model;
+        NmnPanelClient *panel_client;
+
+        status_model = NM_STATUS_MODEL (nm_status_model_new (GTK_TREE_MODEL (model)));
+        panel_client = nmn_panel_client_new (status_model);
+        g_object_unref (status_model);
+
+        if (!panel_client)
+            g_error ("Moblin panel client intialization failed.");
+
+        g_signal_connect (panel_client, "show-begin", G_CALLBACK (panel_client_show), applet);
+        g_signal_connect (panel_client, "show-end", G_CALLBACK (panel_client_hide), applet);
+
+        container = mpl_panel_gtk_get_window (MPL_PANEL_GTK (panel_client));
     }
 
-    gtk_main ();
+    gtk_widget_show (GTK_WIDGET (applet));
+    gtk_container_add (GTK_CONTAINER (container), GTK_WIDGET (applet));
+    gtk_widget_modify_bg (container, GTK_STATE_NORMAL, &gtk_widget_get_style (container)->white);
+    gtk_widget_show (container);
 
-    g_object_unref (applet);
-    nmn_icon_cache_invalidate ();
+    gtk_main ();
+    g_object_unref (model);
+    nm_icon_cache_invalidate ();
 
     return 0;
 }
diff --git a/src/nmn-applet.c b/src/nmn-applet.c
index 1c5df3b..f57af91 100644
--- a/src/nmn-applet.c
+++ b/src/nmn-applet.c
@@ -19,20 +19,18 @@
 
 #include <glib/gi18n.h>
 #include <dbus/dbus-glib-lowlevel.h>
-#include <moblin-panel/mpl-panel-gtk.h>
 #include <nbtk/nbtk-gtk.h>
 #include "nmn-applet.h"
-#include "nmn-nm-data.h"
-#include "nmn-status-icon.h"
-#include "nmn-networks.h"
 #include "nmn-new-connection.h"
 
-G_DEFINE_TYPE (NmnApplet, nmn_applet, G_TYPE_OBJECT)
+#include "nmn-model.h"
+#include "nmn-list.h"
+
+G_DEFINE_TYPE (NmnApplet, nmn_applet, GTK_TYPE_VBOX)
 
 enum {
     PROP_0,
-    PROP_PANEL_CLIENT,
-    PROP_WINDOW,
+    PROP_MODEL,
 
     LAST_PROP
 };
@@ -40,10 +38,7 @@ enum {
 #define GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), NMN_TYPE_APPLET, NmnAppletPrivate))
 
 typedef struct {
-    NmnNMData *nm_data;
-    MplPanelClient *panel_client;
-    GtkWindow *window;
-    NmnStatusIcon *status_icon;
+    NmnModel *model;
 
     GtkWidget *pane;
     GtkWidget *list;
@@ -62,24 +57,27 @@ typedef struct {
     gboolean disposed;
 } NmnAppletPrivate;
 
+static void add_new_connection_hide (GtkWidget *widget, gpointer user_data);
+
 NmnApplet *
-nmn_applet_new (MplPanelClient *panel_client)
+nmn_applet_new (NmnModel *model)
 {
-    g_return_val_if_fail (MPL_IS_PANEL_CLIENT (panel_client), NULL);
+    g_return_val_if_fail (NMN_IS_MODEL (model), NULL);
 
     return NMN_APPLET (g_object_new (NMN_TYPE_APPLET,
-                                     NMN_APPLET_PANEL_CLIENT, panel_client,
+                                     NMN_APPLET_MODEL, model,
                                      NULL));
 }
 
-NmnApplet *
-nmn_applet_new_standalone (GtkWindow *window)
+void
+nmn_applet_show (NmnApplet *applet)
 {
-    g_return_val_if_fail (GTK_IS_WINDOW (window), NULL);
+}
 
-    return NMN_APPLET (g_object_new (NMN_TYPE_APPLET,
-    				     NMN_APPLET_WINDOW, window,
-                                     NULL));
+void
+nmn_applet_hide (NmnApplet *applet)
+{
+    add_new_connection_hide (NULL, applet);
 }
 
 /* enable/disable wifi button */
@@ -91,32 +89,32 @@ enable_wifi_toggled (NbtkGtkLightSwitch *w,
 {
     NmnAppletPrivate *priv = GET_PRIVATE (user_data);
 
-    nmn_nm_data_wifi_toggled (priv->nm_data, active);
+    nmn_model_wifi_toggled (priv->model, active);
 }
 
 static void
-wifi_toggle_set_sensitive (NmnNMData *nm_data,
+wifi_toggle_set_sensitive (NmnModel *model,
                            GtkWidget *widget,
                            gboolean suggested)
 {
-    if (suggested == FALSE || nmn_nm_data_wifi_can_change (nm_data) == FALSE)
+    if (suggested == FALSE || nmn_model_wifi_can_change (model) == FALSE)
         gtk_widget_set_sensitive (widget, FALSE);
     else
         gtk_widget_set_sensitive (widget, TRUE);
 }
 
 static void
-wifi_toggled (NmnNMData *nm_data,
+wifi_toggled (NmnModel *model,
               gboolean active,
               gpointer user_data)
 {
     NmnAppletPrivate *priv = GET_PRIVATE (user_data);
 
-    g_signal_handlers_block_by_func (priv->nm_data, enable_wifi_toggled, user_data);
+    g_signal_handlers_block_by_func (priv->model, enable_wifi_toggled, user_data);
     nbtk_gtk_light_switch_set_active (NBTK_GTK_LIGHT_SWITCH (priv->enable_wifi), active);
-    g_signal_handlers_unblock_by_func (priv->nm_data, enable_wifi_toggled, user_data);
+    g_signal_handlers_unblock_by_func (priv->model, enable_wifi_toggled, user_data);
 
-    wifi_toggle_set_sensitive (priv->nm_data, priv->enable_wifi, TRUE);
+    wifi_toggle_set_sensitive (priv->model, priv->enable_wifi, TRUE);
 }
 
 static void
@@ -127,8 +125,8 @@ enable_wifi_setup (NmnApplet *applet)
     g_signal_connect (priv->enable_wifi, "switch-flipped", G_CALLBACK (enable_wifi_toggled), applet);
     gtk_widget_show (priv->enable_wifi);
 
-    g_signal_connect (priv->nm_data, "wifi-toggled", G_CALLBACK (wifi_toggled), applet);
-    wifi_toggled (priv->nm_data, nmn_nm_data_wifi_get_active (priv->nm_data), applet);
+    g_signal_connect (priv->model, "wifi-toggled", G_CALLBACK (wifi_toggled), applet);
+    wifi_toggled (priv->model, nmn_model_wifi_get_active (priv->model), applet);
 }
 
 /* enable/disable ethernet button */
@@ -140,19 +138,19 @@ enable_ethernet_toggled (NbtkGtkLightSwitch *w,
 {
     NmnAppletPrivate *priv = GET_PRIVATE (user_data);
 
-    nmn_nm_data_ethernet_toggled (priv->nm_data, active);
+    nmn_model_ethernet_toggled (priv->model, active);
 }
 
 static void
-ethernet_toggled (NmnNMData *nm_data,
+ethernet_toggled (NmnModel *model,
                   gboolean active,
                   gpointer user_data)
 {
     NmnAppletPrivate *priv = GET_PRIVATE (user_data);
 
-    g_signal_handlers_block_by_func (priv->nm_data, enable_ethernet_toggled, user_data);
+    g_signal_handlers_block_by_func (priv->model, enable_ethernet_toggled, user_data);
     nbtk_gtk_light_switch_set_active (NBTK_GTK_LIGHT_SWITCH (priv->enable_ethernet), active);
-    g_signal_handlers_unblock_by_func (priv->nm_data, enable_ethernet_toggled, user_data);
+    g_signal_handlers_unblock_by_func (priv->model, enable_ethernet_toggled, user_data);
 }
 
 static void
@@ -163,8 +161,8 @@ enable_ethernet_setup (NmnApplet *applet)
     g_signal_connect (priv->enable_ethernet, "switch-flipped", G_CALLBACK (enable_ethernet_toggled), applet);
     gtk_widget_show (priv->enable_ethernet);
 
-    g_signal_connect (priv->nm_data, "ethernet-toggled", G_CALLBACK (ethernet_toggled), applet);
-    ethernet_toggled (priv->nm_data, nmn_nm_data_ethernet_get_active (priv->nm_data), applet);
+    g_signal_connect (priv->model, "ethernet-toggled", G_CALLBACK (ethernet_toggled), applet);
+    ethernet_toggled (priv->model, nmn_model_ethernet_get_active (priv->model), applet);
 }
 
 /* enable/disable 3G button */
@@ -176,19 +174,19 @@ enable_3g_toggled (NbtkGtkLightSwitch *w,
 {
     NmnAppletPrivate *priv = GET_PRIVATE (user_data);
 
-    nmn_nm_data_modems_toggled (priv->nm_data, active);
+    nmn_model_modems_toggled (priv->model, active);
 }
 
 static void
-modems_toggled (NmnNMData *nm_data,
+modems_toggled (NmnModel *model,
                 gboolean active,
                 gpointer user_data)
 {
     NmnAppletPrivate *priv = GET_PRIVATE (user_data);
 
-    g_signal_handlers_block_by_func (priv->nm_data, enable_3g_toggled, user_data);
+    g_signal_handlers_block_by_func (priv->model, enable_3g_toggled, user_data);
     nbtk_gtk_light_switch_set_active (NBTK_GTK_LIGHT_SWITCH (priv->enable_3g), active);
-    g_signal_handlers_unblock_by_func (priv->nm_data, enable_3g_toggled, user_data);
+    g_signal_handlers_unblock_by_func (priv->model, enable_3g_toggled, user_data);
 }
 
 static void
@@ -199,8 +197,8 @@ enable_3g_setup (NmnApplet *applet)
     g_signal_connect (priv->enable_3g, "switch-flipped", G_CALLBACK (enable_3g_toggled), applet);
     gtk_widget_show (priv->enable_3g);
 
-    g_signal_connect (priv->nm_data, "modems-toggled", G_CALLBACK (modems_toggled), applet);
-    modems_toggled (priv->nm_data, nmn_nm_data_modems_get_active (priv->nm_data), applet);
+    g_signal_connect (priv->model, "modems-toggled", G_CALLBACK (modems_toggled), applet);
+    modems_toggled (priv->model, nmn_model_modems_get_active (priv->model), applet);
 }
 
 /* enable/disable Offline mode button */
@@ -214,25 +212,25 @@ enable_network_toggled (NbtkGtkLightSwitch *w,
 
     gtk_widget_set_sensitive (priv->enable_ethernet, !active);
     gtk_widget_set_sensitive (priv->enable_3g, !active);
-    wifi_toggle_set_sensitive (priv->nm_data, priv->enable_wifi, !active);
+    wifi_toggle_set_sensitive (priv->model, priv->enable_wifi, !active);
 
-    nmn_nm_data_offline_mode_toggled (priv->nm_data, active);
+    nmn_model_offline_mode_toggled (priv->model, active);
 }
 
 static void
-offline_toggled (NmnNMData *nm_data,
+offline_toggled (NmnModel *model,
                  gboolean active,
                  gpointer user_data)
 {
     NmnAppletPrivate *priv = GET_PRIVATE (user_data);
 
-    g_signal_handlers_block_by_func (priv->nm_data, enable_network_toggled, user_data);
+    g_signal_handlers_block_by_func (priv->model, enable_network_toggled, user_data);
     nbtk_gtk_light_switch_set_active (NBTK_GTK_LIGHT_SWITCH (priv->enable_network), active);
-    g_signal_handlers_unblock_by_func (priv->nm_data, enable_network_toggled, user_data);
+    g_signal_handlers_unblock_by_func (priv->model, enable_network_toggled, user_data);
 
     gtk_widget_set_sensitive (priv->enable_3g, !active);
     gtk_widget_set_sensitive (priv->enable_ethernet, !active);
-    wifi_toggle_set_sensitive (priv->nm_data, priv->enable_wifi, !active);
+    wifi_toggle_set_sensitive (priv->model, priv->enable_wifi, !active);
 }
 
 static void
@@ -243,8 +241,8 @@ enable_network_setup (NmnApplet *applet)
     g_signal_connect (priv->enable_network, "switch-flipped", G_CALLBACK (enable_network_toggled), applet);
     gtk_widget_show (priv->enable_network);
 
-    g_signal_connect (priv->nm_data, "offline-mode-toggled", G_CALLBACK (offline_toggled), applet);
-    offline_toggled (priv->nm_data, nmn_nm_data_offline_mode_get_active (priv->nm_data), applet);
+    g_signal_connect (priv->model, "offline-mode-toggled", G_CALLBACK (offline_toggled), applet);
+    offline_toggled (priv->model, nmn_model_offline_mode_get_active (priv->model), applet);
 }
 
 /* add new connection button */
@@ -274,8 +272,8 @@ add_new_connection_setup (NmnApplet *applet)
 {
     NmnAppletPrivate *priv = GET_PRIVATE (applet);
 
-    priv->new_dialog = nmn_new_connection_create (priv->nm_data);
-    g_object_ref_sink (priv->new_dialog);
+    priv->new_dialog = nmn_new_connection_create (priv->model);
+    gtk_box_pack_end (GTK_BOX (applet), priv->new_dialog, TRUE, TRUE, 0);
     gtk_widget_modify_bg (priv->new_dialog, GTK_STATE_NORMAL, &gtk_widget_get_style (priv->new_dialog)->white);
     g_signal_connect (priv->new_dialog, "hide", G_CALLBACK (add_new_connection_hide), applet);
 
@@ -283,104 +281,18 @@ add_new_connection_setup (NmnApplet *applet)
 }
 
 static void
-show_begin_cb (MplPanelClient *panel_client,
-               gpointer user_data)
-{
-    NmnAppletPrivate *priv = GET_PRIVATE (user_data);
-
-    if (!priv->network_list_populated) {
-        nmn_networks_populate (NMN_NETWORKS (priv->list));
-        priv->network_list_populated = TRUE;
-    }
-}
-
-static void
-hide_end_cb (MplPanelClient *panel_client,
-             gpointer user_data)
-{
-    add_new_connection_hide (NULL, user_data);
-}
-
-static DBusGConnection *
-init_dbus (void)
-{
-    DBusGConnection *bus;
-    DBusGProxy *proxy;
-    GError *error = NULL;
-    int request_name_result;
-
-    dbus_connection_set_change_sigpipe (TRUE);
-
-    bus = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);
-    if (!bus) {
-        g_warning ("Could not get the system bus.  Make sure "
-                   "the message bus daemon is running!  Message: %s",
-                   error->message);
-        g_error_free (error);
-        return NULL;
-    }
-
-    dbus_connection_set_exit_on_disconnect (dbus_g_connection_get_connection (bus), FALSE);
-
-    proxy = dbus_g_proxy_new_for_name (bus,
-                                       "org.freedesktop.DBus",
-                                       "/org/freedesktop/DBus",
-                                       "org.freedesktop.DBus");
-
-    if (!dbus_g_proxy_call (proxy, "RequestName", &error,
-                            G_TYPE_STRING, NM_DBUS_SERVICE_USER_SETTINGS,
-                            G_TYPE_UINT, DBUS_NAME_FLAG_DO_NOT_QUEUE,
-                            G_TYPE_INVALID,
-                            G_TYPE_UINT, &request_name_result,
-                            G_TYPE_INVALID)) {
-        g_warning ("Could not acquire the NetworkManagerUserSettings service.\n"
-                   "  Message: '%s'", error->message);
-        g_error_free (error);
-        goto err;
-    }
-
-    if (request_name_result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
-        g_warning ("Could not acquire the NetworkManagerUserSettings service "
-                   "as it is already taken.  Return: %d",
-                   request_name_result);
-        goto err;
-    }
-
-    return bus;
-
- err:
-    dbus_g_connection_unref (bus);
-    return NULL;
-}
-
-static void
 nmn_applet_init (NmnApplet *applet)
 {
     NmnAppletPrivate *priv = GET_PRIVATE (applet);
-    DBusGConnection *bus;
     GtkWidget *w;
     GtkWidget *vbox;
     GtkWidget *frame;
     GtkWidget *table;
     char *label;
 
-    bus = init_dbus ();
-    /* FIXME: Do something nicer here */
-    g_assert (bus);
-
-    priv->nm_data = nmn_nm_data_new (bus);
-    dbus_g_connection_unref (bus);
-
-    priv->status_icon = nmn_status_icon_new ();
-
-    dbus_g_connection_register_g_object (nm_object_get_connection (NM_OBJECT (priv->nm_data)),
-	                                     NM_DBUS_PATH_SETTINGS,
-	                                     G_OBJECT (nmn_nm_data_get_user_settings (priv->nm_data)));
-
-    nmn_status_icon_set_nm_client (priv->status_icon, NM_CLIENT (priv->nm_data));
-
     priv->pane = gtk_hbox_new (FALSE, 6);
     gtk_container_set_border_width (GTK_CONTAINER (priv->pane), 6);
+    gtk_box_pack_start (GTK_BOX (applet), priv->pane, TRUE, TRUE, 0);
 
     /* left side (Networks list, add new connection button) */
     vbox = gtk_vbox_new (FALSE, 6);
@@ -404,7 +316,7 @@ nmn_applet_init (NmnApplet *applet)
 
     w = gtk_scrolled_window_new (NULL, NULL);
     gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (w), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
-    priv->list = nmn_networks_new (priv->nm_data);
+    priv->list = nmn_list_new ();
     gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (w), priv->list);
     gtk_widget_show (priv->list);
     gtk_box_pack_start (GTK_BOX (vbox), w, TRUE, TRUE, 0);
@@ -471,13 +383,6 @@ nmn_applet_init (NmnApplet *applet)
     gtk_table_attach_defaults (GTK_TABLE (table), w, 0, 2, 1, 2);
 
     gtk_widget_show_all (priv->pane);
-
-
-    enable_wifi_setup (applet);
-    enable_ethernet_setup (applet);
-    enable_3g_setup (applet);
-    enable_network_setup (applet);
-    add_new_connection_setup (applet);
 }
 
 static GObject*
@@ -486,9 +391,8 @@ constructor (GType type,
              GObjectConstructParam *construct_params)
 {
     GObject *object;
+    NmnApplet *applet;
     NmnAppletPrivate *priv;
-    GtkWidget *box;
-    GtkWidget *window;
 
     object = G_OBJECT_CLASS (nmn_applet_parent_class)->constructor
         (type, n_construct_params, construct_params);
@@ -496,41 +400,22 @@ constructor (GType type,
     if (!object)
         return NULL;
 
-    priv = GET_PRIVATE (object);
+    applet = NMN_APPLET (object);
+    priv = GET_PRIVATE (applet);
 
-    if (!priv->panel_client && !priv->window) {
+    if (!priv->model) {
         g_warning ("Missing constructor arguments");
         g_object_unref (object);
         return NULL;
     }
-    if (priv->panel_client && priv->window) {
-        g_warning ("You can only use a PanelClient if you don't pass a window");
-        g_object_unref (object);
-        return NULL;
-    }
-
-    box = gtk_vbox_new (FALSE, 0);
-    gtk_widget_show (priv->pane);
-    gtk_box_pack_start (GTK_BOX (box), priv->pane, TRUE, TRUE, 0);
-
-    gtk_widget_hide (priv->new_dialog);
-    gtk_box_pack_end (GTK_BOX (box), priv->new_dialog, TRUE, TRUE, 0);
 
-    gtk_widget_show (box);
-    if (priv->panel_client)
-        window = mpl_panel_gtk_get_window (MPL_PANEL_GTK (priv->panel_client));
-    else
-        window = GTK_WIDGET (priv->window);
-    gtk_container_add (GTK_CONTAINER (window), box);
-    gtk_widget_modify_bg (window, GTK_STATE_NORMAL, &gtk_widget_get_style (window)->white);
-    gtk_widget_show (GTK_WIDGET (window));
-
-    if (priv->panel_client) {
-        g_signal_connect (priv->panel_client, "show-begin", G_CALLBACK (show_begin_cb), object);
-        g_signal_connect (priv->panel_client, "hide-end", G_CALLBACK (hide_end_cb), object);
-    } else {
-        show_begin_cb (NULL, object);
-    }
+    nmn_list_set_model (NMN_LIST (priv->list), GTK_TREE_MODEL (priv->model));
+    enable_wifi_setup (applet);
+    enable_ethernet_setup (applet);
+    enable_3g_setup (applet);
+    enable_network_setup (applet);
+    add_new_connection_setup (applet);
+    add_new_connection_hide (NULL, applet);
 
     return object;
 }
@@ -542,20 +427,9 @@ set_property (GObject *object, guint prop_id,
     NmnAppletPrivate *priv = GET_PRIVATE (object);
 
     switch (prop_id) {
-    case PROP_PANEL_CLIENT:
+    case PROP_MODEL:
         /* Construct only */
-        priv->panel_client = g_value_dup_object (value);
-        if (priv->panel_client)
-            nmn_status_icon_set_panel_client (priv->status_icon, priv->panel_client);
-        break;
-    case PROP_WINDOW:
-    	/* Construct only */
-        priv->window = g_value_dup_object (value);
-        //FIXME we'd like to show a status icon somewhere though
-#if 0
-        if (priv->window)
-            nmn_status_icon_set_panel_client (priv->status_icon, priv->panel_client);
-#endif
+        priv->model = g_value_dup_object (value);
         break;
     default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -570,8 +444,8 @@ get_property (GObject *object, guint prop_id,
     NmnAppletPrivate *priv = GET_PRIVATE (object);
 
     switch (prop_id) {
-    case PROP_PANEL_CLIENT:
-        g_value_set_object (value, priv->panel_client);
+    case PROP_MODEL:
+        g_value_set_object (value, priv->model);
         break;
     default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -589,23 +463,8 @@ dispose (GObject *object)
 
     priv->disposed = TRUE;
 
-    if (priv->new_dialog)
-        gtk_widget_destroy (priv->new_dialog);
-
-    if (priv->pane)
-        g_object_unref (priv->pane);
-
-    if (priv->status_icon)
-        g_object_unref (priv->status_icon);
-
-    if (priv->nm_data)
-        g_object_unref (priv->nm_data);
-
-    if (priv->panel_client)
-        g_object_unref (priv->panel_client);
-
-    if (priv->window)
-        g_object_unref (priv->window);
+    if (priv->model)
+        g_object_unref (priv->model);
 
     G_OBJECT_CLASS (nmn_applet_parent_class)->dispose (object);
 }
@@ -624,17 +483,10 @@ nmn_applet_class_init (NmnAppletClass *class)
 
     /* properties */
     g_object_class_install_property
-        (object_class, PROP_PANEL_CLIENT,
-         g_param_spec_object (NMN_APPLET_PANEL_CLIENT,
-                              "MplPanelClient",
-                              "Panel client",
-                              MPL_TYPE_PANEL_CLIENT,
-                              G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
-    g_object_class_install_property
-        (object_class, PROP_WINDOW,
-         g_param_spec_object (NMN_APPLET_WINDOW,
-                              "GtkWindow",
-                              "Top-level window",
-                              GTK_TYPE_WINDOW,
+        (object_class, PROP_MODEL,
+         g_param_spec_object (NMN_APPLET_MODEL,
+                              "NmnModel",
+                              "NmnModel",
+                              NMN_TYPE_MODEL,
                               G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
 }
diff --git a/src/nmn-applet.h b/src/nmn-applet.h
index d5a47ce..f03cc15 100644
--- a/src/nmn-applet.h
+++ b/src/nmn-applet.h
@@ -20,16 +20,11 @@
 #ifndef NMN_APPLET_H
 #define NMN_APPLET_H
 
-#include <glib-object.h>
 #include <gtk/gtk.h>
-#include <moblin-panel/mpl-panel-client.h>
+#include "nmn-model.h"
 
 G_BEGIN_DECLS
 
-#define APPLET_PREFS_PATH "/apps/nm-applet"
-#define PREF_DISABLE_CONNECTED_NOTIFICATIONS	APPLET_PREFS_PATH "/disable-connected-notifications"
-#define PREF_DISABLE_DISCONNECTED_NOTIFICATIONS	APPLET_PREFS_PATH "/disable-disconnected-notifications"
-
 #define NMN_TYPE_APPLET            (nmn_applet_get_type ())
 #define NMN_APPLET(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMN_TYPE_APPLET, NmnApplet))
 #define NMN_APPLET_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), NMN_TYPE_APPLET, NmnAppletClass))
@@ -37,21 +32,21 @@ G_BEGIN_DECLS
 #define NMN_IS_APPLET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NMN_TYPE_APPLET))
 #define NMN_APPLET_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NMN_TYPE_APPLET, NmnAppletClass))
 
-#define NMN_APPLET_PANEL_CLIENT "panel-client"
-#define NMN_APPLET_WINDOW "window"
+#define NMN_APPLET_MODEL "model"
 
 typedef struct {
-    GObject parent;
+    GtkVBox parent;
 } NmnApplet;
 
 typedef struct {
-    GObjectClass parent;
+    GtkVBoxClass parent;
 } NmnAppletClass;
 
 GType nmn_applet_get_type (void);
 
-NmnApplet     *nmn_applet_new             (MplPanelClient *panel_client);
-NmnApplet     *nmn_applet_new_standalone  (GtkWindow *window);
+NmnApplet *nmn_applet_new  (NmnModel *model);
+void       nmn_applet_show (NmnApplet *applet);
+void       nmn_applet_hide (NmnApplet *applet);
 
 G_END_DECLS
 
diff --git a/src/nmn-item-renderer.c b/src/nmn-item-renderer.c
new file mode 100644
index 0000000..828c121
--- /dev/null
+++ b/src/nmn-item-renderer.c
@@ -0,0 +1,445 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2009 Novell, Inc.
+ */
+
+#include <string.h>
+#include <glib/gi18n.h>
+#include "nmn-item-renderer.h"
+#include "nm-list-item.h"
+#include "nm-icon-cache.h"
+#include "nm-connection-item.h"
+#include "nm-device-item.h"
+#include "nmn-connection-details.h"
+
+G_DEFINE_TYPE (NmnItemRenderer, nmn_item_renderer, GTK_TYPE_EVENT_BOX)
+
+enum {
+    PROP_0,
+    PROP_ITEM,
+
+    LAST_PROP
+};
+
+#define GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), NMN_TYPE_ITEM_RENDERER, NmnItemRendererPrivate))
+
+typedef struct {
+    NMListItem *item;
+
+    GtkBox *vbox; /* child of self */
+    GtkBox *hbox; /* child of vbox */
+
+    GtkImage *icon;
+    GtkLabel *name_and_status;
+    GtkLabel *security_label;
+    GtkWidget *expander;
+    NmnConnectionDetails *details;
+    GtkWidget *connect_button;
+    GtkWidget *remove_button;
+
+    gboolean prelight;
+    GdkColor prelight_color;
+    GdkColor connection_item_color;
+
+    gulong item_changed_id;
+
+    gboolean disposed;
+} NmnItemRendererPrivate;
+
+GtkWidget *
+nmn_item_renderer_new (void)
+{
+    return (GtkWidget *) g_object_new (NMN_TYPE_ITEM_RENDERER, NULL);
+}
+
+NMListItem *
+nmn_item_renderer_get_item (NmnItemRenderer *self)
+{
+    g_return_val_if_fail (NMN_IS_ITEM_RENDERER (self), NULL);
+
+    return GET_PRIVATE (self)->item;
+}
+
+static void
+update_background (NmnItemRenderer *self)
+{
+    NmnItemRendererPrivate *priv = GET_PRIVATE (self);
+    GdkColor *color;
+
+    if (priv->prelight) {
+        color = &priv->prelight_color;
+    } else {
+        if (NM_IS_CONNECTION_ITEM (priv->item) && nm_connection_item_get_connection (NM_CONNECTION_ITEM (priv->item)))
+            color = &priv->connection_item_color;
+        else
+            color = NULL;
+    }
+
+    gtk_widget_modify_bg (GTK_WIDGET (self), GTK_STATE_NORMAL, color);
+}
+
+static void
+update_details (NmnItemRenderer *self)
+{
+    NmnItemRendererPrivate *priv = GET_PRIVATE (self);
+    NMConnection *connection;
+    NMDevice *device;
+    NMSettingIP4Config *setting;
+    NMIP4Config *config;
+
+    if (!priv->details)
+        return;
+
+    connection = (NMConnection *) nm_connection_item_get_connection (NM_CONNECTION_ITEM (priv->item));
+    if (!connection)
+        return;
+
+    device = nm_device_item_get_device (NM_DEVICE_ITEM (priv->item));
+    setting = (NMSettingIP4Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG);
+    
+    if (device && nm_device_get_state (device) == NM_DEVICE_STATE_ACTIVATED)
+        config = nm_device_get_ip4_config (device);
+    else
+        config = NULL;
+
+    nmn_connection_details_set_data (priv->details, setting, config);
+}
+
+static void
+item_changed (NMListItem *item,
+              GParamSpec *spec,
+              gpointer user_data)
+{
+    NmnItemRenderer *self = NMN_ITEM_RENDERER (user_data);
+    NmnItemRendererPrivate *priv = GET_PRIVATE (self);
+    const char *property = spec ? spec->name : NULL;
+    char *str;
+
+    if (!property || !strcmp (property, NM_LIST_ITEM_NAME) || !strcmp (property, NM_LIST_ITEM_STATUS)) {
+        const char *status_str;
+        const char *button_label;
+        NMListItemStatus status;
+
+        status = nm_list_item_get_status (priv->item);
+        switch (status) {
+        case NM_LIST_ITEM_STATUS_CONNECTED:
+            status_str = _("Connected");
+            button_label = _("Disconnect");
+            break;
+        case NM_LIST_ITEM_STATUS_CONNECTING:
+            status_str = _("Connecting...");
+            button_label = _("Disconnect");
+            break;
+        default:
+            status_str = _("Disconnected");
+            button_label = _("Connect");
+            break;
+        }
+
+        if (NM_IS_CONNECTION_ITEM (item) && nm_connection_item_get_connection (NM_CONNECTION_ITEM (item)))
+            str = g_strdup_printf ("<big><b>%s - %s</b></big>", nm_list_item_get_name (item), status_str);
+        else
+            str = g_strdup_printf ("<big><b>%s</b></big>", nm_list_item_get_name (item));
+
+        gtk_label_set_markup (priv->name_and_status, str);
+        g_free (str);
+
+        gtk_button_set_label (GTK_BUTTON (priv->connect_button), button_label);
+        update_details (self);
+    }
+
+    if (!property || !strcmp (property, NM_LIST_ITEM_ICON))
+        gtk_image_set_from_pixbuf (priv->icon, nm_icon_cache_get (nm_list_item_get_icon (item)));
+
+    if (!property || !strcmp (property, NM_LIST_ITEM_SECURITY))
+        gtk_label_set_text (priv->security_label, nm_list_item_get_security (item));
+
+    if (!property || !strcmp (property, NM_LIST_ITEM_SHOW_DELETE)) {
+        if (nm_list_item_get_show_delete (item))
+            gtk_widget_show (priv->remove_button);
+        else
+            gtk_widget_hide (priv->remove_button);
+    }
+
+    if (!property || !strcmp (property, NM_CONNECTION_ITEM_CONNECTION)) {
+        update_background (self);
+
+        if (property && NM_IS_CONNECTION_ITEM (item) && 
+            !nm_connection_item_get_connection (NM_CONNECTION_ITEM (item))) {
+            str = g_strdup_printf ("<big><b>%s</b></big>", nm_list_item_get_name (item));
+            gtk_label_set_markup (priv->name_and_status, str);
+            g_free (str);
+        }
+    }
+}
+
+static void
+connect_button_clicked (GtkButton *button, gpointer user_data)
+{
+    NmnItemRenderer *self = NMN_ITEM_RENDERER (user_data);
+    NMListItem *item;
+
+    item = nmn_item_renderer_get_item (self);
+    if (nm_list_item_get_status (item) == NM_LIST_ITEM_STATUS_DISCONNECTED)
+        nm_list_item_connect (item);
+    else
+        nm_list_item_disconnect (item);
+}
+
+static void
+details_changed (NmnConnectionDetails *details,
+                 gboolean complete,
+                 gpointer user_data)
+{
+    NmnItemRendererPrivate *priv = GET_PRIVATE (user_data);
+
+    gtk_widget_set_sensitive (GTK_WIDGET (priv->connect_button), complete);
+}
+
+NmnConnectionDetails *
+get_details (NmnItemRenderer *self)
+{
+    NmnItemRendererPrivate *priv = GET_PRIVATE (self);
+    GtkWidget *alignment;
+
+    if (priv->details)
+        return priv->details;
+
+    if (!NM_IS_DEVICE_ITEM (priv->item) || !nm_device_item_get_device (NM_DEVICE_ITEM (priv->item)))
+        return NULL;
+
+    priv->details = nmn_connection_details_new ();
+    update_details (self);
+
+    alignment = gtk_alignment_new (0, 0, 0, 0);
+    gtk_container_add (GTK_CONTAINER (alignment), GTK_WIDGET (priv->details));
+    gtk_widget_show (alignment);
+    gtk_box_pack_end (priv->vbox, alignment, FALSE, FALSE, 0);
+
+    g_signal_connect (priv->details, "changed", G_CALLBACK (details_changed), self);
+    details_changed (priv->details, nmn_connection_details_verify (priv->details), self);
+
+    return priv->details;
+}
+
+static void
+advanced_expanded (GtkExpander *expander,
+                   GParamSpec *param_spec,
+                   gpointer user_data)
+{
+    NmnConnectionDetails *details;
+
+    details = get_details (NMN_ITEM_RENDERER (user_data));
+    if (details)
+        g_object_set (details, "visible", gtk_expander_get_expanded (expander), NULL);
+}
+
+static void
+remove_button_clicked (GtkButton *button, gpointer user_data)
+{
+    NmnItemRenderer *self = NMN_ITEM_RENDERER (user_data);
+    GtkDialog *dialog;
+    GtkWidget *label;
+    const char *name;
+    char *label_text;
+    NMListItem *item;
+
+    item = nmn_item_renderer_get_item (self);
+
+    dialog = GTK_DIALOG (gtk_dialog_new_with_buttons (_("Really remove?"),
+                                                      NULL,
+                                                      GTK_DIALOG_MODAL |
+                                                      GTK_DIALOG_DESTROY_WITH_PARENT,
+                                                      GTK_STOCK_CANCEL,
+                                                      GTK_RESPONSE_REJECT,
+                                                      GTK_STOCK_OK,
+                                                      GTK_RESPONSE_ACCEPT,
+                                                      NULL));
+
+    gtk_dialog_set_has_separator (dialog, FALSE);
+    gtk_dialog_set_default_response (dialog, GTK_RESPONSE_ACCEPT);
+    gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
+    gtk_window_set_icon_name (GTK_WINDOW (dialog), GTK_STOCK_DELETE);
+
+    name = nm_list_item_get_name (item);
+    label_text = g_strdup_printf (_("Do you want to remove the '%s' %s network? "
+                                    "This\nwill forget the password and you will"
+                                    " no longer be\nautomatically connected to "
+                                    "'%s'."),
+                                  name,
+                                  nm_list_item_get_type_name (item),
+                                  name);
+
+    label = gtk_label_new (label_text);
+
+    gtk_box_set_spacing (GTK_BOX (dialog->vbox), 12);
+    gtk_box_pack_start (GTK_BOX (dialog->vbox), label, TRUE, TRUE, 6);
+    gtk_widget_show_all (GTK_WIDGET (dialog));
+
+    if (gtk_dialog_run (dialog) == GTK_RESPONSE_ACCEPT)
+        nm_list_item_delete (item);
+
+    gtk_widget_destroy (GTK_WIDGET (dialog));
+}
+
+static void
+init_widgets (NmnItemRenderer *self)
+{
+    NmnItemRendererPrivate *priv = GET_PRIVATE (self);
+    GtkWidget *vbox;
+    GtkWidget *hbox;
+    GtkWidget *w;
+
+    priv->vbox = GTK_BOX (gtk_vbox_new (FALSE, 6));
+    gtk_container_set_border_width (GTK_CONTAINER (priv->vbox), 6);
+    gtk_container_add (GTK_CONTAINER (self), GTK_WIDGET (priv->vbox));
+
+    priv->hbox = GTK_BOX (gtk_hbox_new (FALSE, 6));
+    gtk_container_set_border_width (GTK_CONTAINER (priv->hbox), 6);
+    gtk_box_pack_start (priv->vbox, GTK_WIDGET (priv->hbox), FALSE, FALSE, 0);
+
+    priv->icon = GTK_IMAGE (gtk_image_new ());
+    gtk_box_pack_start (priv->hbox, GTK_WIDGET (priv->icon), FALSE, FALSE, 0);
+
+    vbox = gtk_vbox_new (FALSE, 0);
+    gtk_box_pack_start (priv->hbox, vbox, FALSE, FALSE, 0);
+
+    w = gtk_label_new ("");
+    gtk_label_set_use_markup (GTK_LABEL (w), TRUE);
+    gtk_misc_set_alignment (GTK_MISC (w), 0.0, 0.5);
+    gtk_box_pack_start (GTK_BOX (vbox), w, FALSE, FALSE, 0);
+    priv->name_and_status = GTK_LABEL (w);
+
+    hbox = gtk_hbox_new (FALSE, 12);
+    gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
+
+    w = gtk_label_new ("");
+    gtk_box_pack_start (GTK_BOX (hbox), w, FALSE, FALSE, 0);
+    priv->security_label = GTK_LABEL (w);
+
+    /* FIXME: this should be visibile only for NMDeviceItems */
+    w = gtk_expander_new ("Advanced");
+    gtk_box_pack_start (GTK_BOX (hbox), w, FALSE, FALSE, 0);
+    priv->expander = w;
+    g_signal_connect (w, "notify::expanded", G_CALLBACK (advanced_expanded), self);
+
+    w = gtk_button_new_with_label ("Connect");
+    gtk_box_pack_start (GTK_BOX (hbox), w, FALSE, FALSE, 0);
+    priv->connect_button = w;
+    g_signal_connect (w, "clicked", G_CALLBACK (connect_button_clicked), self);
+
+    /* Remove button */
+    vbox = gtk_vbox_new (FALSE, 0);
+    gtk_box_pack_end (priv->hbox, vbox, FALSE, FALSE, 0);
+
+    w = gtk_button_new ();
+    gtk_button_set_image (GTK_BUTTON (w),
+                          gtk_image_new_from_icon_name ("edit-clear", GTK_ICON_SIZE_MENU));
+
+    gtk_button_set_relief (GTK_BUTTON (w), GTK_RELIEF_NONE);
+    gtk_button_set_image_position (GTK_BUTTON (w), GTK_POS_RIGHT);
+    gtk_widget_set_tooltip_text (w, "Remove connection");
+    gtk_box_pack_start (GTK_BOX (vbox), w, TRUE, FALSE, 0);
+    priv->remove_button = w;
+    g_signal_connect (w, "clicked", G_CALLBACK (remove_button_clicked), self);
+
+    gtk_widget_show_all (GTK_WIDGET (priv->vbox));
+}
+
+void
+nmn_item_renderer_set_item (NmnItemRenderer *self,
+                            NMListItem *item)
+{
+    NmnItemRendererPrivate *priv;
+
+    g_return_if_fail (NMN_IS_ITEM_RENDERER (self));
+    g_return_if_fail (NM_IS_LIST_ITEM (item));
+
+    priv = GET_PRIVATE (self);
+    g_return_if_fail (priv->item == NULL);
+
+    init_widgets (self);
+    priv->item = g_object_ref (item);
+    priv->item_changed_id = g_signal_connect (priv->item, "notify", G_CALLBACK (item_changed), self);
+    item_changed (priv->item, NULL, self);
+}
+
+static gboolean
+enter_notify_event (GtkWidget *widget,
+                    GdkEventCrossing *event)
+{
+    NmnItemRendererPrivate *priv = GET_PRIVATE (widget);
+
+    priv->prelight = TRUE;
+    update_background (NMN_ITEM_RENDERER (widget));
+
+    return TRUE;
+}
+
+static gboolean
+leave_notify_event (GtkWidget *widget,
+                    GdkEventCrossing *event)
+{
+    NmnItemRendererPrivate *priv = GET_PRIVATE (widget);
+
+    if (event->detail != GDK_NOTIFY_INFERIOR) {
+        priv->prelight = FALSE;
+        update_background (NMN_ITEM_RENDERER (widget));
+    }
+
+    return TRUE;
+}
+
+static void
+nmn_item_renderer_init (NmnItemRenderer *item)
+{
+    NmnItemRendererPrivate *priv = GET_PRIVATE (item);
+
+    gdk_color_parse ("#cbcbcb", &priv->prelight_color);
+    gdk_color_parse ("#e8e8e8", &priv->connection_item_color);
+}
+
+static void
+dispose (GObject *object)
+{
+    NmnItemRendererPrivate *priv = GET_PRIVATE (object);
+
+    if (!priv->disposed) {
+        if (priv->item) {
+            g_signal_handler_disconnect (priv->item, priv->item_changed_id);
+            g_object_unref (priv->item);
+        }
+
+        priv->disposed = TRUE;
+    }
+
+    G_OBJECT_CLASS (nmn_item_renderer_parent_class)->dispose (object);
+}
+
+static void
+nmn_item_renderer_class_init (NmnItemRendererClass *class)
+{
+    GObjectClass *object_class = G_OBJECT_CLASS (class);
+    GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
+
+    g_type_class_add_private (object_class, sizeof (NmnItemRendererPrivate));
+
+    object_class->dispose = dispose;
+
+    widget_class->enter_notify_event = enter_notify_event;
+    widget_class->leave_notify_event = leave_notify_event;
+}
diff --git a/src/nmn-item-renderer.h b/src/nmn-item-renderer.h
new file mode 100644
index 0000000..a43337e
--- /dev/null
+++ b/src/nmn-item-renderer.h
@@ -0,0 +1,51 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2009 Novell, Inc.
+ */
+
+#ifndef NMN_ITEM_RENDERER_H
+#define NMN_ITEM_RENDERER_H
+
+#include <gtk/gtk.h>
+#include <nm-list-item.h>
+
+#define NMN_TYPE_ITEM_RENDERER            (nmn_item_renderer_get_type ())
+#define NMN_ITEM_RENDERER(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMN_TYPE_ITEM_RENDERER, NmnItemRenderer))
+#define NMN_ITEM_RENDERER_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), NMN_TYPE_ITEM_RENDERER, NmnItemRendererClass))
+#define NMN_IS_ITEM_RENDERER(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMN_TYPE_ITEM_RENDERER))
+#define NMN_IS_ITEM_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NMN_TYPE_ITEM_RENDERER))
+#define NMN_ITEM_RENDERER_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NMN_TYPE_ITEM_RENDERER, NmnItemRendererClass))
+
+typedef struct {
+    GtkEventBox parent;
+
+    GtkTreeIter iter;
+    int index;
+} NmnItemRenderer;
+
+typedef struct {
+    GtkEventBoxClass parent;
+} NmnItemRendererClass;
+
+GType nmn_item_renderer_get_type (void);
+
+GtkWidget  *nmn_item_renderer_new      (void);
+NMListItem *nmn_item_renderer_get_item (NmnItemRenderer *self);
+void        nmn_item_renderer_set_item (NmnItemRenderer *self,
+                                        NMListItem *item);
+
+#endif /* NMN_ITEM_RENDERER_H */
diff --git a/src/nmn-list.c b/src/nmn-list.c
index b712981..fc6a70c 100644
--- a/src/nmn-list.c
+++ b/src/nmn-list.c
@@ -18,19 +18,27 @@
  */
 
 #include <string.h>
+#include <glib/gi18n.h>
+#include <nm-list-model.h>
+#include <nm-list-item.h>
 #include "nmn-list.h"
-
-#define NMN_DRAG_TARGET "NMN_DRAG_TARGET"
-static const GtkTargetEntry nmn_list_targets [] = {
-    { NMN_DRAG_TARGET, GTK_TARGET_SAME_APP, 0 },
-};
+#include "nmn-model.h"
+#include "nmn-item-renderer.h"
 
 G_DEFINE_TYPE (NmnList, nmn_list, GTK_TYPE_VBOX)
 
-#define NMN_LIST_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), NMN_TYPE_LIST, NmnListPrivate))
+#define GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), NMN_TYPE_LIST, NmnListPrivate))
 
 typedef struct {
-    GtkWidget *dnd_window;
+    GtkTreeModel *model;
+    GSList *rows;
+
+    gulong row_deleted_id;
+    gulong row_inserted_id;
+    gulong rows_reordered_id;
+    guint layout_idle_id;
+
+    gboolean disposed;
 } NmnListPrivate;
 
 GtkWidget *
@@ -39,319 +47,381 @@ nmn_list_new (void)
     return GTK_WIDGET (g_object_new (NMN_TYPE_LIST, NULL));
 }
 
-typedef struct {
-    GtkWidget *needle;
-    int counter;
-    int found;
-} ContainerPosInfo;
-
-static void
-get_position_cb (GtkWidget *widget, gpointer data)
+GtkWidget *
+nmn_list_new_with_model (GtkTreeModel *model)
 {
-    ContainerPosInfo *info = (ContainerPosInfo *) data;
+    GtkWidget *list;
+
+    list = nmn_list_new ();
+    if (list)
+        nmn_list_set_model (NMN_LIST (list), model);
+
+    return list;
+}
 
-    if (widget == info->needle)
-        info->found = info->counter;
+static const char *
+get_punctuation (guint items_left)
+{
+    if (items_left > 1)
+        return ", ";
+    if (items_left == 1)
+        return _(" and ");
 
-    info->counter++;
+    /* items_left == 0 */
+    return ".";
 }
 
-static int
-container_get_position (GtkContainer *container, GtkWidget *child)
+static char *
+get_empty_text (NmnModel *model)
 {
-    ContainerPosInfo info;
+    GString *string;
 
-    info.counter = 0;
-    info.found = -1;
-    info.needle = child;
+    string = g_string_new (_("Sorry, we can't find any networks."));
 
-    gtk_container_foreach (container, get_position_cb, &info);
+    if (nmn_model_offline_mode_get_active (model)) {
+        g_string_append (string, _(" You could try disabling Offline mode."));
+    } else {
+        gboolean wifi_enabled;
+        gboolean ethernet_enabled;
+        gboolean modem_enabled;
+        guint disabled_count = 0;
+
+        wifi_enabled = nmn_model_wifi_get_active (model);
+        if (!wifi_enabled)
+            disabled_count++;
+
+        ethernet_enabled = nmn_model_ethernet_get_active (model);
+        if (!ethernet_enabled)
+            disabled_count++;
+
+        modem_enabled = nmn_model_modems_get_active (model);
+        if (!modem_enabled)
+            disabled_count++;
+
+        if (disabled_count > 0) {
+            g_string_append (string, _(" You could try turning on "));
+
+            if (!wifi_enabled) {
+                g_string_append (string, _("WiFi"));
+                g_string_append (string, get_punctuation (--disabled_count));
+            }
+
+            if (!ethernet_enabled) {
+                g_string_append (string, _("Wired"));
+                g_string_append (string, get_punctuation (--disabled_count));
+            }
+
+            if (!modem_enabled) {
+                g_string_append (string, _("3G"));
+                g_string_append (string, get_punctuation (--disabled_count));
+            }
+        }
+    }
 
-    return info.found;
+    return g_string_free (string, FALSE);
 }
 
 static void
-drag_begin (GtkWidget *widget, GdkDragContext *drag_context, gpointer user_data)
+nmn_list_clear (NmnList *self)
 {
-    NmnListPrivate *priv = NMN_LIST_GET_PRIVATE (user_data);
-
-    g_object_set_data (G_OBJECT (widget), "original-location",
-                       GINT_TO_POINTER (container_get_position (GTK_CONTAINER (user_data), widget)));
-
-    g_object_ref (widget);
-    gtk_container_remove (GTK_CONTAINER (user_data), widget);
+    GtkContainer *container = GTK_CONTAINER (self);
+    GList *list;
+    GList *iter;
 
-    priv->dnd_window = gtk_window_new (GTK_WINDOW_POPUP);
-    gtk_container_add (GTK_CONTAINER (priv->dnd_window), widget);
-    g_object_unref (widget);
+    list = gtk_container_get_children (container);
+    for (iter = list; iter; iter = iter->next)
+        gtk_container_remove (container, GTK_WIDGET (iter->data));
 
-    gtk_drag_set_icon_widget (drag_context, priv->dnd_window, -2, -2);
+    g_list_free (list);
 }
 
 static void
-drag_data_get (GtkWidget *widget,
-               GdkDragContext *context,
-               GtkSelectionData *data,
-               guint info,
-               guint time)
+switches_flipped (NmnList *self)
 {
-    if (data->target == gdk_atom_intern_static_string (NMN_DRAG_TARGET)) {
-        gtk_selection_data_set (data,
-                                data->target,
-                                8,
-                                (void*) &widget,
-                                sizeof (gpointer));
-    }
+    NmnListPrivate *priv = GET_PRIVATE (self);
+    char *txt, *s;
+    GtkWidget *w;
+
+    if (priv->rows || !NMN_IS_MODEL (priv->model))
+        return;
+
+    nmn_list_clear (self);
+    
+    txt = get_empty_text (NMN_MODEL (priv->model));
+    s = g_strdup_printf ("<big><b>%s</b></big>", txt);
+    g_free (txt);
+
+    w = gtk_label_new (NULL);
+    gtk_misc_set_alignment (GTK_MISC (w), 0.0, 0.5);
+    gtk_label_set_markup (GTK_LABEL (w), s);
+    g_free (s);
+
+    gtk_box_pack_start (GTK_BOX (self), w, FALSE, FALSE, 0);
+    gtk_widget_show (w);
 }
 
-static gboolean
-drag_failed (GtkWidget *widget,
-             GdkDragContext *drag_context,
-             GtkDragResult result,
-             gpointer user_data)
+static void
+nmn_list_layout (NmnList *self)
 {
-    if (result != GTK_DRAG_RESULT_SUCCESS) {
-        NmnListPrivate *priv = NMN_LIST_GET_PRIVATE (user_data);
+    NmnListPrivate *priv = GET_PRIVATE (self);
+    GSList *iter;
 
-        g_debug ("drag failed");
-        g_object_ref (widget);
-        gtk_container_remove (GTK_CONTAINER (priv->dnd_window), widget);
-        gtk_box_pack_start (GTK_BOX (user_data), widget, FALSE, FALSE, 0);
-        gtk_box_reorder_child (GTK_BOX (user_data), widget,
-                               GPOINTER_TO_INT (g_object_get_data (G_OBJECT (widget), "original-location")));
+    if (priv->layout_idle_id) {
+        g_source_remove (priv->layout_idle_id);
+        priv->layout_idle_id = 0;
+    }
 
-        g_object_unref (widget);
+    /* FIXME: This could probably be much more efficient, especially for cases where
+       a single item is added to the end of the list or a single item changes it's location */
 
-        return TRUE;
+    nmn_list_clear (self);
+    switches_flipped (self);
+
+    for (iter = priv->rows; iter; iter = iter->next) {
+        NmnItemRenderer *renderer = iter->data;
+        NMListItem *item;
+
+        item = nmn_item_renderer_get_item (renderer);
+        if (!item) {
+            GtkTreeIter iter;
+
+            if (gtk_tree_model_get_flags (priv->model) & GTK_TREE_MODEL_ITERS_PERSIST)
+                iter = renderer->iter;
+            else {
+                GtkTreePath *path;
+
+                path = gtk_tree_path_new_from_indices (renderer->index, -1);
+                gtk_tree_model_get_iter (priv->model, &iter, path);
+                gtk_tree_path_free (path);
+            }
+
+            gtk_tree_model_get (priv->model, &iter, NM_LIST_MODEL_COL_ITEM, &item, -1);
+            if (item)
+                nmn_item_renderer_set_item (renderer, item);
+        }
+
+        if (item) {
+            gtk_box_pack_start (GTK_BOX (self), GTK_WIDGET (renderer), FALSE, FALSE, 0);
+            gtk_widget_show (GTK_WIDGET (renderer));
+        }
     }
+}
+
+static gboolean
+queue_layout_cb (gpointer data)
+{
+    NmnListPrivate *priv = GET_PRIVATE (data);
+
+    priv->layout_idle_id = 0;
+    nmn_list_layout (NMN_LIST (data));
 
     return FALSE;
 }
 
 static void
-drag_end (GtkWidget *widget, GdkDragContext *drag_context, gpointer user_data)
+queue_layout (NmnList *self)
 {
-    NmnListPrivate *priv = NMN_LIST_GET_PRIVATE (user_data);
+    NmnListPrivate *priv = GET_PRIVATE (self);
 
-    g_debug ("drag end");
-    GTK_BIN (priv->dnd_window)->child = NULL;
-    gtk_widget_destroy (priv->dnd_window);
+    if (!priv->layout_idle_id)
+        priv->layout_idle_id = g_idle_add (queue_layout_cb, self);
 }
 
-static gint
-compare_items (gconstpointer a,
-               gconstpointer b)
+static void
+model_row_deleted (GtkTreeModel *model,
+                   GtkTreePath *path,
+                   gpointer user_data)
 {
-    NmnItem *a_item = NMN_ITEM (a);
-    NmnItem *b_item = NMN_ITEM (b);
-    char *a_label;
-    char *b_label;
-    guint a_priority;
-    guint b_priority;
-    gint result;
-
-    a_priority = nmn_item_get_priority (a_item);
-    b_priority = nmn_item_get_priority (b_item);
-
-    if (a_priority < b_priority)
-        return 1;
-
-    if (a_priority > b_priority)
-        return -1;
-
-    a_label = nmn_item_get_name (a_item);
-    b_label = nmn_item_get_name (b_item);
-
-    if (a_label) {
-        if (b_label)
-            result = strcmp (a_label, b_label);
-        else
-            result = 1;
-    } else
-        result = -1;
-
-    g_free (a_label);
-    g_free (b_label);
-
-    return result;
+    NmnList *self = NMN_LIST (user_data);
+    NmnListPrivate *priv = GET_PRIVATE (self);
+    GSList *list;
+    GSList *next;
+    NmnItemRenderer *renderer;
+    int index;
+
+    index = gtk_tree_path_get_indices(path)[0];
+    list = g_slist_nth (priv->rows, index);
+    renderer = list->data;
+    g_object_unref (renderer);
+
+    for (next = list->next; next; next = next->next) {
+        renderer = next->data;
+        renderer->index--;
+    }
+  
+    priv->rows = g_slist_delete_link (priv->rows, list);
+    queue_layout (self);
 }
 
 static void
-nmn_list_sort (NmnList *list)
+model_row_inserted (GtkTreeModel *model,
+                    GtkTreePath *path,
+                    GtkTreeIter *iter,
+                    gpointer user_data)
 {
-    GList *items;
-    GList *iter;
-    int i;
-
-    items = gtk_container_get_children (GTK_CONTAINER (list));
-    items = g_list_sort (items, compare_items);
-    i = 0;
+    NmnList *self = NMN_LIST (user_data);
+    NmnListPrivate *priv = GET_PRIVATE (self);
+    NmnItemRenderer *renderer;
+    GSList *list;
+    int index;
+
+    index = gtk_tree_path_get_indices (path)[0];
+
+    renderer = (NmnItemRenderer *) nmn_item_renderer_new ();
+    renderer->index = index;
+
+    if (gtk_tree_model_get_flags (model) & GTK_TREE_MODEL_ITERS_PERSIST)
+        renderer->iter = *iter;
+
+    priv->rows = g_slist_insert (priv->rows, g_object_ref_sink (renderer), index);
+  
+    list = g_slist_nth (priv->rows, index + 1);
+    for (; list; list = list->next) {
+        renderer = list->data;
+        renderer->index++;
+    }
 
-    for (iter = items; iter; iter = iter->next)
-        gtk_box_reorder_child (GTK_BOX (list), GTK_WIDGET (iter->data), i++);
+    queue_layout (self);
 }
 
-void
-nmn_list_add_item (NmnList *list,
-                   NmnItem *item)
+static void
+model_rows_reordered (GtkTreeModel *model,
+                      GtkTreePath *path,
+                      GtkTreeIter *iter,
+                      gint *new_order,
+                      gpointer user_data)
 {
-    g_return_if_fail (NMN_IS_LIST (list));
-    g_return_if_fail (NMN_IS_ITEM (item));
-
-    /* FIXME: See http://bugzilla.moblin.org/show_bug.cgi?id=5499
-       and https://bugzilla.novell.com/show_bug.cgi?id=528715 */
-#if 0
-    gtk_drag_source_set (GTK_WIDGET (item), GDK_BUTTON1_MASK, 
-                         nmn_list_targets, G_N_ELEMENTS (nmn_list_targets),
-                         GDK_ACTION_MOVE);
-#endif
-
-    g_signal_connect (item, "drag-begin",
-                      G_CALLBACK (drag_begin),
-                      list);
-
-    g_signal_connect (item, "drag-data-get",
-                      G_CALLBACK (drag_data_get),
-                      list);
-
-    g_signal_connect (item, "drag-failed",
-                      G_CALLBACK (drag_failed),
-                      list);
-
-    g_signal_connect (item, "drag-end",
-                      G_CALLBACK (drag_end),
-                      list);
-
-    g_signal_connect_swapped (item, "notify",
-                              G_CALLBACK (nmn_list_sort),
-                              list);
-
-    gtk_box_pack_start (GTK_BOX (list), GTK_WIDGET (item), FALSE, FALSE, 0);
-    nmn_list_sort (list);
-    gtk_widget_show (GTK_WIDGET (item));
-}
+    NmnList *self = NMN_LIST (user_data);
+    NmnListPrivate *priv = GET_PRIVATE (self);
+    GSList *list;
+    NmnItemRenderer **renderer_array;
+    GSList *rows = NULL;
+    gint *order;
+    int length;
+    int i;
 
+    length = gtk_tree_model_iter_n_children (model, NULL);
 
-typedef struct {
-    GtkWidget *match;
-    gint match_position;
-    gint y;
-    gint counter;
-} FindActiveInfo;
+    order = g_new (int, length);
+    for (i = 0; i < length; i++)
+        order[new_order[i]] = i;
 
-static void
-find_active_item_cb (GtkWidget *widget, gpointer data)
-{
-    FindActiveInfo *info = (FindActiveInfo *) data;
+    renderer_array = g_new (NmnItemRenderer *, length);
+    for (i = 0, list = priv->rows; list != NULL; list = list->next, i++)
+        renderer_array[order[i]] = list->data;
+    g_free (order);
 
-    if (widget->allocation.y <= info->y && widget->allocation.y + widget->allocation.height > info->y) {
-        info->match = widget;
-        info->match_position = info->counter;
+    for (i = length - 1; i >= 0; i--) {
+        renderer_array[i]->index = i;
+        rows = g_slist_prepend (rows, renderer_array[i]);
     }
+  
+    g_free (renderer_array);
+    g_slist_free (priv->rows);
+    priv->rows = rows;
 
-    info->counter++;
+    queue_layout (self);
 }
 
 static gboolean
-find_active_item (GtkContainer *container, gint y, GtkWidget **active_widget, gint *active_position)
+model_foreach_cb (GtkTreeModel *model,
+                  GtkTreePath *path,
+                  GtkTreeIter *iter,
+                  gpointer user_data)
 {
-    FindActiveInfo info;
-
-    info.match = NULL;
-    info.match_position = 0;
-    info.counter = 0;
-    info.y = y;
-    gtk_container_foreach (container, find_active_item_cb, &info);
+    model_row_inserted (model, path, iter, user_data);
 
-    if (info.match) {
-        *active_widget = info.match;
-        *active_position = info.match_position;
-    }
-
-    return info.match != NULL;
+    return FALSE;
 }
 
-static gboolean
-nmn_list_drag_drop (GtkWidget *widget,
-                    GdkDragContext *context,
-                    gint x,
-                    gint y,
-                    guint time)
+void
+nmn_list_set_model (NmnList *list,
+                    GtkTreeModel *model)
 {
-    GdkAtom target, item_target;
+    NmnListPrivate *priv;
+
+    g_return_if_fail (NMN_IS_LIST (list));
+
+    priv = GET_PRIVATE (list);
 
-    g_debug ("drag_drop1");
-    target = gtk_drag_dest_find_target (widget, context, NULL);
-    item_target = gdk_atom_intern_static_string (NMN_DRAG_TARGET);
+    if (model == priv->model)
+        return;
 
-    if (target == item_target) {
-        gtk_drag_get_data (widget, context, target, time);
-        g_debug ("drag_drop2");
-        return TRUE;
+    if (priv->model) {
+        if (NMN_IS_MODEL (priv->model))
+            g_signal_handlers_disconnect_by_func (priv->model, switches_flipped, list);
+
+        g_signal_handler_disconnect (priv->model, priv->row_deleted_id);
+        g_signal_handler_disconnect (priv->model, priv->row_inserted_id);
+        g_signal_handler_disconnect (priv->model, priv->rows_reordered_id);
+
+        g_object_unref (priv->model);
     }
 
-    g_debug ("drag_drop3");
-    return FALSE;
+    priv->model = model;
+
+    if (priv->model) {
+        g_object_ref (priv->model);
+
+        priv->row_deleted_id = g_signal_connect (model, "row-deleted", G_CALLBACK (model_row_deleted), list);
+        priv->row_inserted_id = g_signal_connect (model, "row-inserted", G_CALLBACK (model_row_inserted), list);
+        priv->rows_reordered_id = g_signal_connect (model, "rows-reordered", G_CALLBACK (model_rows_reordered), list);
+
+        gtk_tree_model_foreach (model, model_foreach_cb, list);
+
+        if (NMN_IS_MODEL (model)) {
+            g_signal_connect_swapped (model, "ethernet-toggled",     G_CALLBACK (switches_flipped), list);
+            g_signal_connect_swapped (model, "wifi-toggled",         G_CALLBACK (switches_flipped), list);
+            g_signal_connect_swapped (model, "modems-toggled",       G_CALLBACK (switches_flipped), list);
+            g_signal_connect_swapped (model, "offline-mode-toggled", G_CALLBACK (switches_flipped), list);
+        }
+    }
 }
 
-static void
-nmn_list_drag_data_received (GtkWidget *widget,
-                             GdkDragContext *context,
-                             gint x,
-                             gint y,
-                             GtkSelectionData *data,
-                             guint info,
-                             guint time)
+GtkTreeModel *
+nmn_list_get_model (NmnList *list)
 {
-    GtkWidget *source_widget;
-    NmnListPrivate *priv = NMN_LIST_GET_PRIVATE (widget);
-
-    g_debug ("data_received1");
-    source_widget = gtk_drag_get_source_widget (context);
-    if (source_widget && data->target == gdk_atom_intern_static_string (NMN_DRAG_TARGET)) {
-        GtkWidget *active_widget;
-        gint active_position = -1;
-
-        g_debug ("data_received2");
-        find_active_item (GTK_CONTAINER (widget), y, &active_widget, &active_position);
-
-        g_object_ref (source_widget);
-        g_print ("child %p, source_widget: %p target: %p\n", GTK_BIN (priv->dnd_window)->child, source_widget, (void*) data->data);
-        gtk_container_remove (GTK_CONTAINER (priv->dnd_window), source_widget);
-        gtk_box_pack_start (GTK_BOX (widget), source_widget, FALSE, FALSE, 0);
-        gtk_box_reorder_child (GTK_BOX (widget), source_widget, active_position);
-        g_object_unref (source_widget);
-
-        gtk_drag_finish (context, TRUE, FALSE, time);
-    } else {
-        g_debug ("data_received3");
-        gtk_drag_finish (context, FALSE, FALSE, time);
-    }
+    g_return_val_if_fail (NMN_IS_LIST (list), NULL);
 
-    g_debug ("data_received4");
+    return GET_PRIVATE (list)->model;
 }
 
+/*****************************************************************************/
+
 static void
 nmn_list_init (NmnList *list)
 {
-    gtk_drag_dest_set (GTK_WIDGET (list),
-                       GTK_DEST_DEFAULT_ALL,
-                       nmn_list_targets,
-                       G_N_ELEMENTS (nmn_list_targets),
-                       GDK_ACTION_MOVE);
-
     gtk_box_set_homogeneous (GTK_BOX (list), FALSE);
-    gtk_box_set_spacing (GTK_BOX (list), 12);
+    gtk_box_set_spacing (GTK_BOX (list), 6);
+    gtk_container_set_border_width (GTK_CONTAINER (list), 6);
+}
+
+static void
+dispose (GObject *object)
+{
+    NmnListPrivate *priv = GET_PRIVATE (object);
+
+    if (!priv->disposed) {
+        if (priv->layout_idle_id)
+            g_source_remove (priv->layout_idle_id);
+
+        g_slist_foreach (priv->rows, (GFunc) g_object_unref, NULL);
+        g_slist_free (priv->rows);
+
+        nmn_list_set_model (NMN_LIST (object), NULL);
+
+        priv->disposed = TRUE;
+    }
+
+    G_OBJECT_CLASS (nmn_list_parent_class)->dispose (object);
 }
 
 static void
 nmn_list_class_init (NmnListClass *class)
 {
     GObjectClass *object_class = G_OBJECT_CLASS (class);
-    GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
 
     g_type_class_add_private (object_class, sizeof (NmnListPrivate));
 
-    widget_class->drag_drop = nmn_list_drag_drop;
-    widget_class->drag_data_received = nmn_list_drag_data_received;
+    object_class->dispose = dispose;
 }
diff --git a/src/nmn-list.h b/src/nmn-list.h
index f1d62f3..8d6a4b4 100644
--- a/src/nmn-list.h
+++ b/src/nmn-list.h
@@ -21,7 +21,6 @@
 #define NMN_LIST_H
 
 #include <gtk/gtk.h>
-#include <nmn-item.h>
 
 #define NMN_TYPE_LIST            (nmn_list_get_type ())
 #define NMN_LIST(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMN_TYPE_LIST, NmnList))
@@ -40,8 +39,11 @@ typedef struct {
 
 GType nmn_list_get_type (void);
 
-GtkWidget *nmn_list_new (void);
-void       nmn_list_add_item (NmnList *list,
-                              NmnItem *item);
+GtkWidget   *nmn_list_new            (void);
+GtkWidget   *nmn_list_new_with_model (GtkTreeModel *model);
+void         nmn_list_set_model      (NmnList *list,
+                                      GtkTreeModel *model);
+
+GtkTreeModel *nmn_list_get_model      (NmnList *list);
 
 #endif /* NMN_LIST_H */
diff --git a/src/nmn-model.c b/src/nmn-model.c
new file mode 100644
index 0000000..0e14490
--- /dev/null
+++ b/src/nmn-model.c
@@ -0,0 +1,433 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2009 Novell, Inc.
+ */
+
+#include <nm-remote-settings-system.h>
+#include "nmn-model.h"
+#include "nm-list-model.h"
+#include "nm-gconf-settings.h"
+#include "nm-list-item.h"
+#include "nm-ethernet-item.h"
+#include "nm-wifi-item.h"
+#include "nm-gsm-item.h"
+#include "nm-cdma-item.h"
+
+G_DEFINE_TYPE (NmnModel, nmn_model, GTK_TYPE_TREE_MODEL_FILTER)
+
+enum {
+    ETHERNET_TOGGLED,
+    WIFI_TOGGLED,
+    MODEMS_TOGGLED,
+    OFFLINE_MODE_TOGGLED,
+
+    LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL];
+
+#define GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), NMN_TYPE_MODEL, NmnModelPrivate))
+
+typedef struct {
+    NMClient *client;
+    NMSettingsInterface *user_settings;
+    NMSettingsInterface *system_settings;
+
+    gboolean ethernet_active;
+    gboolean wifi_active;
+    gboolean modems_active;
+    gboolean offline_mode_active;
+
+    gboolean disposed;
+} NmnModelPrivate;
+
+NmnModel *
+nmn_model_new (void)
+{
+    NmnModel *model;
+    NMClient *client;
+    NMListModel *child_model;
+
+    client = nm_client_new ();
+    child_model = nm_list_model_new (client);
+    g_object_unref (client);
+
+    model = (NmnModel *) g_object_new (NMN_TYPE_MODEL,
+                                       "child-model", child_model,
+                                       NULL);
+
+    g_object_unref (child_model);
+
+    return model;
+}
+
+NMClient *
+nmn_model_get_client (NmnModel *self)
+{
+    g_return_val_if_fail (NMN_IS_MODEL (self), NULL);
+
+    return GET_PRIVATE (self)->client;
+}
+
+NMSettingsInterface *
+nmn_model_get_user_settings (NmnModel *self)
+{
+    g_return_val_if_fail (NMN_IS_MODEL (self), NULL);
+
+    return GET_PRIVATE (self)->user_settings;
+}
+
+NMSettingsInterface *
+nmn_model_get_system_settings (NmnModel *self)
+{
+    g_return_val_if_fail (NMN_IS_MODEL (self), NULL);
+
+    return GET_PRIVATE (self)->system_settings;
+}
+
+gboolean
+nmn_model_ethernet_get_active (NmnModel *self)
+{
+    g_return_val_if_fail (NMN_IS_MODEL (self), FALSE);
+
+    return GET_PRIVATE (self)->ethernet_active;
+}
+
+void
+nmn_model_ethernet_toggled (NmnModel *self,
+                            gboolean active)
+{
+    NmnModelPrivate *priv;
+
+    g_return_if_fail (NMN_IS_MODEL (self));
+
+    priv = GET_PRIVATE (self);
+    if (priv->ethernet_active != active) {
+        /* FIXME: Save in gconf? */
+        priv->ethernet_active = active;
+        gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (self));
+
+        g_signal_emit (self, signals[ETHERNET_TOGGLED], 0, active);
+    }
+}
+
+gboolean
+nmn_model_wifi_can_change (NmnModel *self)
+{
+    g_return_val_if_fail (NMN_IS_MODEL (self), FALSE);
+
+    return nm_client_wireless_hardware_get_enabled (nmn_model_get_client (self));
+}
+
+gboolean
+nmn_model_wifi_get_active (NmnModel *self)
+{
+    g_return_val_if_fail (NMN_IS_MODEL (self), FALSE);
+
+    return GET_PRIVATE (self)->wifi_active;
+}
+
+static void
+wifi_toggled_internal (NmnModel *self, gboolean active)
+{
+    NmnModelPrivate *priv = GET_PRIVATE (self);
+
+    if (priv->wifi_active != active) {
+        /* FIXME: Save in gconf? */
+        priv->wifi_active = active;
+        gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (self));
+
+        g_signal_emit (self, signals[WIFI_TOGGLED], 0, active);
+    }
+}
+
+void
+nmn_model_wifi_toggled (NmnModel *self,
+                        gboolean active)
+{
+    g_return_if_fail (NMN_IS_MODEL (self));
+
+    wifi_toggled_internal (self, active);
+    nm_client_wireless_set_enabled (nmn_model_get_client (self), active);
+}
+
+gboolean
+nmn_model_modems_get_active (NmnModel *self)
+{
+    g_return_val_if_fail (NMN_IS_MODEL (self), FALSE);
+
+    return GET_PRIVATE (self)->modems_active;
+}
+
+void
+nmn_model_modems_toggled (NmnModel *self,
+                          gboolean active)
+{
+    NmnModelPrivate *priv;
+
+    g_return_if_fail (NMN_IS_MODEL (self));
+
+    priv = GET_PRIVATE (self);
+    if (priv->modems_active != active) {
+        /* FIXME: Save in gconf? */
+        priv->modems_active = active;
+        gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (self));
+
+        g_signal_emit (self, signals[MODEMS_TOGGLED], 0, active);
+    }
+}
+
+gboolean
+nmn_model_offline_mode_get_active (NmnModel *self)
+{
+    g_return_val_if_fail (NMN_IS_MODEL (self), FALSE);
+
+    return GET_PRIVATE (self)->offline_mode_active;
+}
+
+static void
+offline_mode_toggled_internal (NmnModel *self, gboolean active)
+{
+    NmnModelPrivate *priv = GET_PRIVATE (self);
+
+    if (priv->offline_mode_active != active) {
+        /* FIXME: Save in gconf? */
+        priv->offline_mode_active = active;
+        gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (self));
+
+        g_signal_emit (self, signals[OFFLINE_MODE_TOGGLED], 0, active);
+    }
+}
+
+void
+nmn_model_offline_mode_toggled (NmnModel *self,
+                                gboolean active)
+{
+    g_return_if_fail (NMN_IS_MODEL (self));
+
+    offline_mode_toggled_internal (self, active);
+    nm_client_sleep (nmn_model_get_client (self), active);
+}
+
+static void
+nm_client_state_changed (NMClient *client,
+                         GParamSpec *gobject,
+                         gpointer user_data)
+{
+    offline_mode_toggled_internal (NMN_MODEL (user_data), nm_client_get_state (client) == NM_STATE_ASLEEP);
+}
+
+static void
+nm_wireless_state_changed (NMClient *client,
+                           GParamSpec *gobject,
+                           gpointer user_data)
+{
+    wifi_toggled_internal (NMN_MODEL (user_data), nm_client_wireless_get_enabled (client));
+}
+
+static gboolean
+model_row_visible_func (GtkTreeModel *model,
+                        GtkTreeIter  *iter,
+                        gpointer      data)
+{
+    NMListItem *item = NULL;
+    gboolean visible = FALSE;
+
+    gtk_tree_model_get (model, iter, NM_LIST_MODEL_COL_ITEM, &item, -1);
+    if (item) {
+        NmnModelPrivate *priv = GET_PRIVATE (data);
+
+        if (priv->offline_mode_active)
+            visible = FALSE;
+        else if (NM_IS_WIFI_ITEM (item))
+            visible = priv->wifi_active;
+        else if (NM_IS_ETHERNET_ITEM (item))
+            visible = priv->ethernet_active;
+        else if (NM_IS_GSM_ITEM (item))
+            visible = priv->modems_active;
+        else if (NM_IS_CDMA_ITEM (item))
+            visible = priv->modems_active;
+
+        g_object_unref (item);
+    }
+
+    return visible;
+}
+
+static gboolean
+request_dbus_name (DBusGConnection *bus)
+{
+    DBusGProxy *proxy;
+    GError *error = NULL;
+    int request_name_result;
+
+    dbus_connection_set_change_sigpipe (TRUE);
+    dbus_connection_set_exit_on_disconnect (dbus_g_connection_get_connection (bus), FALSE);
+
+    proxy = dbus_g_proxy_new_for_name (bus,
+                                       "org.freedesktop.DBus",
+                                       "/org/freedesktop/DBus",
+                                       "org.freedesktop.DBus");
+
+    if (!dbus_g_proxy_call (proxy, "RequestName", &error,
+                            G_TYPE_STRING, NM_DBUS_SERVICE_USER_SETTINGS,
+                            G_TYPE_UINT, DBUS_NAME_FLAG_DO_NOT_QUEUE,
+                            G_TYPE_INVALID,
+                            G_TYPE_UINT, &request_name_result,
+                            G_TYPE_INVALID)) {
+        g_warning ("Could not acquire the NetworkManagerUserSettings service.\n"
+                   "  Message: '%s'", error->message);
+        g_error_free (error);
+        return FALSE;
+    }
+
+    if (request_name_result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
+        g_warning ("Could not acquire the NetworkManagerUserSettings service "
+                   "as it is already taken.  Return: %d",
+                   request_name_result);
+        return FALSE;
+    }
+
+    return TRUE;
+}
+
+static void
+nmn_model_init (NmnModel *model)
+{
+    NmnModelPrivate *priv = GET_PRIVATE (model);
+
+    gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (model),
+                                            model_row_visible_func, model, NULL);
+
+    /* FIXME: Load from gconf? */
+    priv->ethernet_active = TRUE;
+    priv->wifi_active = TRUE;
+    priv->modems_active = TRUE;
+    priv->offline_mode_active = FALSE;
+}
+
+static void
+constructed (GObject *object)
+{
+    NmnModelPrivate *priv = GET_PRIVATE (object);
+    NMListModel *child_model;
+    DBusGConnection *bus;
+
+    if (G_OBJECT_CLASS (nmn_model_parent_class)->constructed)
+        G_OBJECT_CLASS (nmn_model_parent_class)->constructed (object);
+
+    child_model = NM_LIST_MODEL (gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (object)));
+
+    priv->client = nm_list_model_get_client (child_model);
+    bus = nm_object_get_connection (NM_OBJECT (priv->client));
+
+    priv->user_settings = NM_SETTINGS_INTERFACE (nm_gconf_settings_new (bus));
+    priv->system_settings = NM_SETTINGS_INTERFACE (nm_remote_settings_system_new (bus));
+
+    nm_list_model_add_settings (child_model, priv->user_settings);
+    nm_list_model_add_settings (child_model, priv->system_settings);
+
+    g_signal_connect (priv->client,
+                      "notify::" NM_CLIENT_STATE,
+                      G_CALLBACK (nm_client_state_changed),
+                      object);
+
+    g_signal_connect (priv->client,
+                      "notify::" NM_CLIENT_WIRELESS_ENABLED,
+                      G_CALLBACK (nm_wireless_state_changed),
+                      object);
+
+    g_signal_connect (priv->client,
+                      "notify::" NM_CLIENT_WIRELESS_HARDWARE_ENABLED,
+                      G_CALLBACK (nm_wireless_state_changed),
+                      object);
+
+    nm_wireless_state_changed (priv->client, NULL, object);
+    nm_client_state_changed (priv->client, NULL, object);
+
+    if (request_dbus_name (bus))
+        dbus_g_connection_register_g_object (bus, NM_DBUS_PATH_SETTINGS, G_OBJECT (priv->user_settings));
+}
+
+static void
+dispose (GObject *object)
+{
+    NmnModelPrivate *priv = GET_PRIVATE (object);
+
+    if (!priv->disposed) {
+        g_signal_handlers_disconnect_by_func (priv->client, gtk_tree_model_filter_refilter, object);
+
+        g_object_unref (priv->user_settings);
+        g_object_unref (priv->system_settings);
+
+        priv->disposed = TRUE;
+    }
+
+    G_OBJECT_CLASS (nmn_model_parent_class)->dispose (object);
+}
+
+static void
+nmn_model_class_init (NmnModelClass *class)
+{
+    GObjectClass *object_class = G_OBJECT_CLASS (class);
+
+    g_type_class_add_private (object_class, sizeof (NmnModelPrivate));
+
+    object_class->constructed = constructed;
+    object_class->dispose = dispose;
+
+    /* signals */
+    signals[ETHERNET_TOGGLED] = g_signal_new 
+        ("ethernet-toggled",
+         G_OBJECT_CLASS_TYPE (class),
+         G_SIGNAL_RUN_LAST,
+         G_STRUCT_OFFSET (NmnModelClass, ethernet_toggled),
+         NULL, NULL,
+         g_cclosure_marshal_VOID__BOOLEAN,
+         G_TYPE_NONE, 1,
+         G_TYPE_BOOLEAN);
+
+    signals[WIFI_TOGGLED] = g_signal_new 
+        ("wifi-toggled",
+         G_OBJECT_CLASS_TYPE (class),
+         G_SIGNAL_RUN_LAST,
+         G_STRUCT_OFFSET (NmnModelClass, wifi_toggled),
+         NULL, NULL,
+         g_cclosure_marshal_VOID__BOOLEAN,
+         G_TYPE_NONE, 1,
+         G_TYPE_BOOLEAN);
+
+    signals[MODEMS_TOGGLED] = g_signal_new 
+        ("modems-toggled",
+         G_OBJECT_CLASS_TYPE (class),
+         G_SIGNAL_RUN_LAST,
+         G_STRUCT_OFFSET (NmnModelClass, modems_toggled),
+         NULL, NULL,
+         g_cclosure_marshal_VOID__BOOLEAN,
+         G_TYPE_NONE, 1,
+         G_TYPE_BOOLEAN);
+
+    signals[OFFLINE_MODE_TOGGLED] = g_signal_new 
+        ("offline-mode-toggled",
+         G_OBJECT_CLASS_TYPE (class),
+         G_SIGNAL_RUN_LAST,
+         G_STRUCT_OFFSET (NmnModelClass, offline_mode_toggled),
+         NULL, NULL,
+         g_cclosure_marshal_VOID__BOOLEAN,
+         G_TYPE_NONE, 1,
+         G_TYPE_BOOLEAN);
+}
diff --git a/src/nmn-model.h b/src/nmn-model.h
new file mode 100644
index 0000000..a74e3e4
--- /dev/null
+++ b/src/nmn-model.h
@@ -0,0 +1,80 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2009 Novell, Inc.
+ */
+
+#ifndef NMN_MODEL_H
+#define NMN_MODEL_H
+
+#include <gtk/gtk.h>
+#include <nm-client.h>
+#include <nm-settings-interface.h>
+
+#define NMN_TYPE_MODEL            (nmn_model_get_type ())
+#define NMN_MODEL(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMN_TYPE_MODEL, NmnModel))
+#define NMN_MODEL_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), NMN_TYPE_MODEL, NmnModelClass))
+#define NMN_IS_MODEL(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMN_TYPE_MODEL))
+#define NMN_IS_MODEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NMN_TYPE_MODEL))
+#define NMN_MODEL_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NMN_TYPE_MODEL, NmnModelClass))
+
+typedef struct {
+    GtkTreeModelFilter parent;
+} NmnModel;
+
+typedef struct {
+    GtkTreeModelFilterClass parent;
+
+    /* Signals */
+    void (*ethernet_toggled) (NmnModel *self,
+                              gboolean active);
+
+    void (*wifi_toggled) (NmnModel *self,
+                          gboolean active);
+
+    void (*modems_toggled) (NmnModel *self,
+                            gboolean active);
+
+    void (*offline_mode_toggled) (NmnModel *self,
+                                  gboolean active);
+} NmnModelClass;
+
+GType nmn_model_get_type (void);
+
+NmnModel *nmn_model_new        (void);
+NMClient *nmn_model_get_client (NmnModel *self);
+
+NMSettingsInterface *nmn_model_get_user_settings   (NmnModel *self);
+NMSettingsInterface *nmn_model_get_system_settings (NmnModel *self);
+
+gboolean    nmn_model_ethernet_get_active     (NmnModel *self); 
+void        nmn_model_ethernet_toggled        (NmnModel *self,
+                                               gboolean active);
+
+gboolean    nmn_model_wifi_can_change         (NmnModel *self);
+gboolean    nmn_model_wifi_get_active         (NmnModel *self); 
+void        nmn_model_wifi_toggled            (NmnModel *self,
+                                               gboolean active);
+
+gboolean    nmn_model_modems_get_active       (NmnModel *self); 
+void        nmn_model_modems_toggled          (NmnModel *self,
+                                               gboolean active);
+
+gboolean    nmn_model_offline_mode_get_active (NmnModel *self);
+void        nmn_model_offline_mode_toggled    (NmnModel *self,
+                                               gboolean active);
+
+#endif /* NMN_MODEL_H */
diff --git a/src/nmn-new-connection.c b/src/nmn-new-connection.c
index 4f97615..917833c 100644
--- a/src/nmn-new-connection.c
+++ b/src/nmn-new-connection.c
@@ -32,8 +32,10 @@
 #include <nm-setting-ip4-config.h>
 #include <nm-utils.h>
 #include "nmn-new-connection.h"
-#include "nma-gconf-settings.h"
-#include "nmn-wifi-list.h"
+#include "nm-list-model.h"
+#include "nm-wifi-item.h"
+#include "nm-gconf-settings.h"
+#include "nmn-list.h"
 #include "nmn-mobile-providers.h"
 #include "wireless-dialog.h"
 
@@ -41,7 +43,7 @@ G_DEFINE_TYPE (NmnNewConnection, nmn_new_connection, GTK_TYPE_VBOX)
 
 enum {
     PROP_0,
-    PROP_NM_DATA,
+    PROP_MODEL,
 
     LAST_PROP
 };
@@ -49,7 +51,7 @@ enum {
 #define GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), NMN_TYPE_NEW_CONNECTION, NmnNewConnectionPrivate))
 
 typedef struct {
-    NmnNMData *nm_data;
+    NmnModel *model;
 
     /* WiFi widgets */
     GtkWidget *wifi_list_container;
@@ -66,12 +68,12 @@ typedef struct {
 } NmnNewConnectionPrivate;
 
 GtkWidget *
-nmn_new_connection_create (NmnNMData *nm_data)
+nmn_new_connection_create (NmnModel *model)
 {
-    g_return_val_if_fail (NMN_IS_NM_DATA (nm_data), NULL);
+    g_return_val_if_fail (NMN_IS_MODEL (model), NULL);
 
     return GTK_WIDGET (g_object_new (NMN_TYPE_NEW_CONNECTION,
-                                     NMN_NEW_CONNECTION_NM_DATA, nm_data,
+                                     NMN_NEW_CONNECTION_MODEL, model,
                                      NULL));
 }
 
@@ -105,16 +107,16 @@ save_timestamp_cb (NMSettingsConnectionInterface *connection,
 }
 
 static gboolean
-save_connection (NmnNMData *data, NMConnection *connection)
+save_connection (NmnModel *model, NMConnection *connection)
 {
     NMSettingConnection *s_con;
     NMSettingsConnectionInterface *gconf_connection;
-    NMAGConfSettings *settings;
+    NMGConfSettings *settings;
 
-    settings = NMA_GCONF_SETTINGS (nmn_nm_data_get_user_settings (data));
+    settings = NM_GCONF_SETTINGS (nmn_model_get_user_settings (model));
 
     gconf_connection = nm_settings_interface_get_connection_by_path (NM_SETTINGS_INTERFACE (settings),
-								     nm_connection_get_path (connection));
+                                                                     nm_connection_get_path (connection));
     if (!gconf_connection)
         return FALSE;
     s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION));
@@ -136,9 +138,9 @@ wifi_dialog_done (NMAWirelessDialog *dialog,
         goto done;
 
     connection = nma_wireless_dialog_get_connection (dialog);
-    save_connection (priv->nm_data, connection);
+    save_connection (priv->model, connection);
 
-    nm_client_activate_connection (NM_CLIENT (priv->nm_data),
+    nm_client_activate_connection (nmn_model_get_client (priv->model),
                                    NM_DBUS_SERVICE_USER_SETTINGS,
                                    nm_connection_get_path (connection),
                                    nma_wireless_dialog_get_device (dialog),
@@ -157,18 +159,44 @@ wifi_search (GtkButton *button, gpointer user_data)
     NmnNewConnectionPrivate *priv = GET_PRIVATE (user_data);
     GtkWidget *dialog;
 
-    dialog = nma_wireless_dialog_hidden_new (NM_CLIENT (priv->nm_data));
+    dialog = nma_wireless_dialog_hidden_new (nmn_model_get_client (priv->model));
     g_signal_connect (dialog, "done", G_CALLBACK (wifi_dialog_done), user_data);
     nma_wireless_dialog_show (NMA_WIRELESS_DIALOG (dialog));
 }
 
+static gboolean
+wifi_model_visible_func (GtkTreeModel *model,
+                         GtkTreeIter  *iter,
+                         gpointer      data)
+{
+    NMListItem *item = NULL;
+    gboolean visible = FALSE;
+
+    gtk_tree_model_get (model, iter, NM_LIST_MODEL_COL_ITEM, &item, -1);
+    if (item) {
+        /* Show unconfigured WiFi items */
+        if (NM_IS_WIFI_ITEM (item) && !nm_connection_item_get_connection (NM_CONNECTION_ITEM (item)))
+            visible = TRUE;
+
+        g_object_unref (item);
+    }
+
+    return visible;
+}
+
 static void
 wifi_page_init (NmnNewConnection *connection)
 {
     NmnNewConnectionPrivate *priv = GET_PRIVATE (connection);
+    GtkTreeModel *wifi_model;
+
+    wifi_model = gtk_tree_model_filter_new (GTK_TREE_MODEL (priv->model), NULL);
+    gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (wifi_model),
+                                            wifi_model_visible_func, NULL, NULL);
 
-    priv->wifi_list = nmn_wifi_list_new (priv->nm_data);
-    g_signal_connect (priv->wifi_list, "connect-requested", G_CALLBACK (connect_requested), connection);
+    priv->wifi_list = nmn_list_new_with_model (wifi_model);
+    g_object_unref (wifi_model);
+    //g_signal_connect (priv->wifi_list, "connect-requested", G_CALLBACK (connect_requested), connection);
     gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (priv->wifi_list_container), priv->wifi_list);
     gtk_widget_show_all (priv->wifi_list);
 }
@@ -183,11 +211,13 @@ static gboolean
 mobile_have_device (NmnNewConnection *connection, NmnMobileProviderType *type)
 {
     NmnNewConnectionPrivate *priv = GET_PRIVATE (connection);
+    NMClient *client;
     const GPtrArray *devices;
     int i;
     gboolean found = FALSE;
 
-    devices = nm_client_get_devices (NM_CLIENT (priv->nm_data));
+    client = nmn_model_get_client (priv->model);
+    devices = nm_client_get_devices (client);
     for (i = 0; !found && devices && i < devices->len; i++) {
         NMDevice *device = NM_DEVICE (g_ptr_array_index (devices, i));
 
@@ -212,7 +242,7 @@ mobile_status_update (NmnNewConnection *connection)
     NmnMobileProviderType type;
     gboolean found;
 
-    if (!nmn_nm_data_modems_get_active (priv->nm_data)) {
+    if (!nmn_model_modems_get_active (priv->model)) {
         found = FALSE;
         gtk_label_set_text (GTK_LABEL (priv->mobile_label), _("3G disabled"));
     } else {
@@ -394,6 +424,8 @@ mobile_tree_selection_changed (GtkTreeSelection *selection,
         gtk_tree_model_get (model, &iter, MOBILE_COL_METHOD, &method, -1);
 
     gtk_widget_set_sensitive (priv->mobile_save, method != NULL);
+    if (method)
+        nmn_mobile_access_method_unref (method);
 }
 
 static NMConnection *
@@ -517,13 +549,19 @@ mobile_save_clicked (GtkButton *button, gpointer user_data)
         nmn_mobile_provider_unref (provider);
 
         if (connection) {
-            nma_gconf_settings_add_connection (NMA_GCONF_SETTINGS (nmn_nm_data_get_user_settings (priv->nm_data)),
-                                               connection);
+            nm_gconf_settings_add_connection (NM_GCONF_SETTINGS (nmn_model_get_user_settings (priv->model)),
+                                              connection);
             g_object_unref (connection);
         }
 
         gtk_widget_hide (GTK_WIDGET (self));
     }
+
+    if (provider)
+        nmn_mobile_provider_unref (provider);
+
+    if (method)
+        nmn_mobile_access_method_unref (method);
 }
 
 static void
@@ -543,12 +581,13 @@ static void
 mobile_page_init (NmnNewConnection *connection)
 {
     NmnNewConnectionPrivate *priv = GET_PRIVATE (connection);
+    NMClient *client = nmn_model_get_client (priv->model);
 
     g_signal_connect (connection, "realize", G_CALLBACK (mobile_list_populate), NULL);
-    g_signal_connect (priv->nm_data, "device-added", G_CALLBACK (mobile_device_added), connection);
-    g_signal_connect_swapped (priv->nm_data, "device-removed", G_CALLBACK (mobile_status_update), connection);
+    g_signal_connect (client, "device-added", G_CALLBACK (mobile_device_added), connection);
+    g_signal_connect_swapped (client, "device-removed", G_CALLBACK (mobile_status_update), connection);
     
-    priv->mobile_toggled_id = g_signal_connect_swapped (priv->nm_data, "modems-toggled",
+    priv->mobile_toggled_id = g_signal_connect_swapped (priv->model, "modems-toggled",
                                                         G_CALLBACK (mobile_status_update),
                                                         connection);
 
@@ -647,7 +686,7 @@ constructor (GType type,
 
     priv = GET_PRIVATE (object);
 
-    if (!priv->nm_data) {
+    if (!priv->model) {
         g_warning ("Missing constructor arguments");
         g_object_unref (object);
         return NULL;
@@ -666,9 +705,9 @@ set_property (GObject *object, guint prop_id,
     NmnNewConnectionPrivate *priv = GET_PRIVATE (object);
 
     switch (prop_id) {
-    case PROP_NM_DATA:
+    case PROP_MODEL:
         /* Construct only */
-        priv->nm_data = g_value_dup_object (value);
+        priv->model = g_value_dup_object (value);
         break;
     default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -683,8 +722,8 @@ get_property (GObject *object, guint prop_id,
     NmnNewConnectionPrivate *priv = GET_PRIVATE (object);
 
     switch (prop_id) {
-    case PROP_NM_DATA:
-        g_value_set_object (value, priv->nm_data);
+    case PROP_MODEL:
+        g_value_set_object (value, priv->model);
         break;
     default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -702,10 +741,10 @@ dispose (GObject *object)
 
     priv->disposed = TRUE;
 
-    g_signal_handler_disconnect (priv->nm_data, priv->mobile_toggled_id);
+    g_signal_handler_disconnect (priv->model, priv->mobile_toggled_id);
 
-    if (priv->nm_data)
-        g_object_unref (priv->nm_data);
+    if (priv->model)
+        g_object_unref (priv->model);
 
     G_OBJECT_CLASS (nmn_new_connection_parent_class)->dispose (object);
 }
@@ -725,10 +764,10 @@ nmn_new_connection_class_init (NmnNewConnectionClass *class)
 
     /* properties */
     g_object_class_install_property
-        (object_class, PROP_NM_DATA,
-         g_param_spec_object (NMN_NEW_CONNECTION_NM_DATA,
-                              "NmnNMData",
-                              "NmnNMData",
-                              NMN_TYPE_NM_DATA,
+        (object_class, PROP_MODEL,
+         g_param_spec_object (NMN_NEW_CONNECTION_MODEL,
+                              "NmnModel",
+                              "NmnModel",
+                              NMN_TYPE_MODEL,
                               G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
 }
diff --git a/src/nmn-new-connection.h b/src/nmn-new-connection.h
index c0af684..886b531 100644
--- a/src/nmn-new-connection.h
+++ b/src/nmn-new-connection.h
@@ -21,7 +21,7 @@
 #define NMN_NEW_CONNECTION_H
 
 #include <gtk/gtk.h>
-#include "nmn-nm-data.h"
+#include "nmn-model.h"
 
 #define NMN_TYPE_NEW_CONNECTION            (nmn_new_connection_get_type ())
 #define NMN_NEW_CONNECTION(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMN_TYPE_NEW_CONNECTION, NmnNewConnection))
@@ -30,7 +30,7 @@
 #define NMN_IS_NEW_CONNECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NMN_TYPE_NEW_CONNECTION))
 #define NMN_NEW_CONNECTION_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NMN_TYPE_NEW_CONNECTION, NmnNewConnectionClass))
 
-#define NMN_NEW_CONNECTION_NM_DATA "nm-data"
+#define NMN_NEW_CONNECTION_MODEL "model"
 
 typedef struct {
     GtkVBox parent;
@@ -42,6 +42,6 @@ typedef struct {
 
 GType nmn_new_connection_get_type (void);
 
-GtkWidget *nmn_new_connection_create (NmnNMData *nm_data);
+GtkWidget *nmn_new_connection_create (NmnModel *model);
 
 #endif /* NMN_NEW_CONNECTION_H */
diff --git a/src/nmn-panel-client.c b/src/nmn-panel-client.c
new file mode 100644
index 0000000..138b66f
--- /dev/null
+++ b/src/nmn-panel-client.c
@@ -0,0 +1,388 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2009 Novell, Inc.
+ */
+
+#include <string.h>
+#include <glib/gi18n.h>
+#include <gdk/gdk.h>
+#include <gtk/gtk.h>
+#include <libnotify/notify.h>
+#include <moblin-panel/mpl-panel-common.h>
+#include <nm-device-ethernet.h>
+#include <nm-device-wifi.h>
+#include <nm-gsm-device.h>
+#include <nm-cdma-device.h>
+#include <nm-utils.h>
+
+#include "nmn-panel-client.h"
+
+#define ACTIVATION_STEPS 6
+
+G_DEFINE_TYPE (NmnPanelClient, nmn_panel_client, MPL_TYPE_PANEL_GTK)
+
+enum {
+    PROP_0,
+    PROP_MODEL,
+
+    LAST_PROP
+};
+
+#define GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), NMN_TYPE_PANEL_CLIENT, NmnPanelClientPrivate))
+
+typedef struct {
+    NMStatusModel *model;
+
+    NMListItem *item;
+    guint animation_id;
+    guint animation_step;
+
+    /* Saved from previous item */
+    NMListItemStatus status;
+    char *connection_type;
+    char *connection_name;
+} NmnPanelClientPrivate;
+
+NmnPanelClient *
+nmn_panel_client_new (NMStatusModel *model)
+{
+    g_return_val_if_fail (NM_IS_STATUS_MODEL (model), NULL);
+
+    return (NmnPanelClient *) g_object_new (NMN_TYPE_PANEL_CLIENT,
+                                           "name", MPL_PANEL_NETWORK,
+                                           "tooltip", _("network"),
+                                           "stylesheet", THEME_PATH "/network-manager-netbook.css",
+                                           "button-style", "unknown",
+                                           "toolbar-service", TRUE,
+                                           NMN_PANEL_CLIENT_MODEL, model,
+                                           NULL);
+
+}
+
+static void
+stop_activation_animation (NmnPanelClient *self)
+{
+    NmnPanelClientPrivate *priv = GET_PRIVATE (self);
+
+    if (priv->animation_id) {
+        g_source_remove (priv->animation_id);
+        priv->animation_id = 0;
+        priv->animation_step = 0;
+    }
+}
+
+static gboolean
+activation_animation (gpointer data)
+{
+    NmnPanelClient *self = NMN_PANEL_CLIENT (data);
+    NmnPanelClientPrivate *priv = GET_PRIVATE (self);
+    char *image;
+
+    if (++priv->animation_step > ACTIVATION_STEPS)
+        priv->animation_step = 1;
+
+    image = g_strdup_printf ("progress-%02d", priv->animation_step);
+    mpl_panel_client_request_button_style (MPL_PANEL_CLIENT (self), image);
+    g_free (image);
+
+    return TRUE;
+}
+
+/* FIXME: This is all pretty gross */
+static const char *
+massage_icon (const char *original)
+{
+    static char *icon = NULL;
+
+    if (icon) {
+        g_free (icon);
+        icon = NULL;
+    }
+
+    if (!original)
+        return NULL;
+
+    if (g_str_has_prefix (original, "nm-"))
+        icon = g_strdup (original + 3);
+    else
+        icon = g_strdup (original);
+
+    if (g_str_has_suffix (icon, "-active") || g_str_has_suffix (icon, "-normal"))
+        icon[strlen(icon) - 7] = '\0';
+
+    return icon;
+}
+
+static void
+update_icon (NmnPanelClient *self)
+{
+    NmnPanelClientPrivate *priv = GET_PRIVATE (self);
+    NMListItemStatus status;
+
+    status = priv->item ? nm_list_item_get_status (priv->item) : NM_LIST_ITEM_STATUS_DISCONNECTED;
+    switch (status) {
+    case NM_LIST_ITEM_STATUS_CONNECTING:
+        if (priv->animation_id == 0) {
+            priv->animation_id = g_timeout_add (200, activation_animation, self);
+            activation_animation (self);
+        }
+        break;
+    case NM_LIST_ITEM_STATUS_DISCONNECTED:
+        stop_activation_animation (self);
+        mpl_panel_client_request_button_style (MPL_PANEL_CLIENT (self), "no-network");
+        break;
+    case NM_LIST_ITEM_STATUS_CONNECTED:
+        stop_activation_animation (self);
+        mpl_panel_client_request_button_style (MPL_PANEL_CLIENT (self),
+                                               massage_icon (nm_list_item_get_icon (priv->item)));
+        
+        break;
+    }
+}
+
+static void
+update_notification (NmnPanelClient *self)
+{
+    NmnPanelClientPrivate *priv = GET_PRIVATE (self);
+    const char *title;
+    char *msg;
+    const char *connection_type;
+    const char *connection_name;
+    const char *icon;
+    NMListItemStatus status;
+
+    if (priv->item) {
+        status = nm_list_item_get_status (priv->item);
+        connection_type = nm_list_item_get_type_name (priv->item);
+        connection_name = nm_list_item_get_name (priv->item);
+        icon = nm_list_item_get_icon (priv->item);
+    } else {
+        status = NM_LIST_ITEM_STATUS_DISCONNECTED;
+        connection_type = NULL;
+        connection_name = NULL;
+        icon = NULL;
+    }
+
+    if (priv->status == NM_LIST_ITEM_STATUS_DISCONNECTED && status == NM_LIST_ITEM_STATUS_CONNECTED) {
+        title = _("Network connected");
+
+        if (connection_type) {
+            if (connection_name)
+                msg = g_strdup_printf (_("You're now connected to %s, a %s network"),
+                                       connection_name, connection_type);
+            else
+                msg = g_strdup_printf (_("You're now connected to %s network"), connection_type);
+        } else
+            msg = g_strdup (_("You're now connected to network"));
+    } else if (priv->status == NM_LIST_ITEM_STATUS_CONNECTED && status == NM_LIST_ITEM_STATUS_DISCONNECTED) {
+        title = _("Network lost");
+
+        if (priv->connection_type) {
+            if (priv->connection_name)
+                msg = g_strdup_printf (_("Sorry, we've lost your %s connection to %s"),
+                                       priv->connection_type, priv->connection_name);
+            else
+                msg = g_strdup_printf (_("Sorry, we've lost your %s connection"), priv->connection_type);
+        } else
+            msg = g_strdup (_("Sorry, we've lost your connection"));
+    } else {
+        title = NULL;
+        msg = NULL;
+    }
+
+    if (title && msg) {
+        NotifyNotification *note;
+
+        note = notify_notification_new (title, msg, icon, NULL);
+        notify_notification_set_timeout (note, 10000);
+        notify_notification_show (note, NULL);
+        g_object_unref (note);
+        g_free (msg);
+
+        priv->status = status;
+        g_free (priv->connection_type);
+        priv->connection_type = connection_type ? g_strdup (connection_type) : NULL;
+        g_free (priv->connection_name);
+        priv->connection_name = connection_name ? g_strdup (connection_name) : NULL;
+    }
+}
+
+static void
+update_tooltip (NmnPanelClient *self)
+{
+    NmnPanelClientPrivate *priv = GET_PRIVATE (self);
+    char *tip;
+    const char *connection_type;
+    const char *connection_name;
+    NMListItemStatus status;
+
+    status = priv->item ? nm_list_item_get_status (priv->item) : NM_LIST_ITEM_STATUS_DISCONNECTED;
+    switch (status) {
+    case NM_LIST_ITEM_STATUS_DISCONNECTED:
+        tip = g_strdup_printf (_("networks - not connected"));
+        break;
+    case NM_LIST_ITEM_STATUS_CONNECTING:
+        tip = g_strdup_printf (_("networks - connecting"));
+        break;
+    case NM_LIST_ITEM_STATUS_CONNECTED:
+        connection_type = nm_list_item_get_type_name (priv->item);
+        connection_name = nm_list_item_get_name (priv->item);
+
+        if (connection_type) {
+            if (connection_name)
+                tip = g_strdup_printf (_("networks - %s - %s"), connection_name, connection_type);
+            else
+                tip = g_strdup_printf (_("networks - %s"), connection_type);
+        } else
+            tip = g_strdup (_("networks - connected"));
+
+        break;
+    }
+
+    mpl_panel_client_request_tooltip (MPL_PANEL_CLIENT (self), tip);
+    g_free (tip);
+}
+
+static void
+item_status_changed (NMListItem *item,
+                     GParamSpec *spec,
+                     gpointer user_data)
+{
+    NmnPanelClient *self = NMN_PANEL_CLIENT (user_data);
+
+    update_notification (self);
+    update_tooltip (self);
+    update_icon (self);
+}
+
+static void
+model_changed (NMStatusModel *model,
+               NMListItem *active_item,
+               gpointer user_data)
+{
+    NmnPanelClient *self = NMN_PANEL_CLIENT (user_data);
+    NmnPanelClientPrivate *priv = GET_PRIVATE (self);
+
+    if (active_item == priv->item)
+        return;
+
+    if (priv->item)
+        g_signal_handlers_disconnect_by_func (priv->item, item_status_changed, self);
+
+    priv->item = active_item;
+
+    if (active_item) {
+        g_signal_connect (active_item, "notify::" NM_LIST_ITEM_STATUS, G_CALLBACK (item_status_changed), self);
+        g_signal_connect (active_item, "notify::" NM_LIST_ITEM_ICON, G_CALLBACK (item_status_changed), self);
+    }
+    
+    item_status_changed (active_item, NULL, self);
+}
+
+/*****************************************************************************/
+
+static void
+nmn_panel_client_init (NmnPanelClient *self)
+{
+    notify_init ("network-manager-netbook");
+    mpl_panel_client_set_height_request (MPL_PANEL_CLIENT (self), 499);
+}
+
+static void
+set_property (GObject *object, guint prop_id,
+              const GValue *value, GParamSpec *pspec)
+{
+    NmnPanelClientPrivate *priv = GET_PRIVATE (object);
+
+    switch (prop_id) {
+    case PROP_MODEL:
+        /* Construct only */
+        priv->model = 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)
+{
+    NmnPanelClientPrivate *priv = GET_PRIVATE (object);
+
+    switch (prop_id) {
+    case PROP_MODEL:
+        g_value_set_object (value, priv->model);
+        break;
+    default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+        break;
+    }
+}
+
+static void
+constructed (GObject *object)
+{
+    NmnPanelClientPrivate *priv = GET_PRIVATE (object);
+
+    if (G_OBJECT_CLASS (nmn_panel_client_parent_class)->constructed)
+        G_OBJECT_CLASS (nmn_panel_client_parent_class)->constructed (object);
+
+    g_signal_connect (priv->model, "changed", G_CALLBACK (model_changed), object);
+    item_status_changed (NULL, NULL, object);
+}
+
+static void
+finalize (GObject *object)
+{
+    NmnPanelClientPrivate *priv = GET_PRIVATE (object);
+
+    stop_activation_animation (NMN_PANEL_CLIENT (object));
+
+    g_free (priv->connection_type);
+    g_free (priv->connection_name);
+
+    if (priv->model)
+        g_object_unref (priv->model);
+
+    notify_uninit ();
+
+    G_OBJECT_CLASS (nmn_panel_client_parent_class)->finalize (object);
+}
+
+static void
+nmn_panel_client_class_init (NmnPanelClientClass *klass)
+{
+    GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+    g_type_class_add_private (object_class, sizeof (NmnPanelClientPrivate));
+
+    object_class->set_property = set_property;
+    object_class->get_property = get_property;
+    object_class->constructed = constructed;
+    object_class->finalize = finalize;
+
+    /* Properties */
+    g_object_class_install_property
+        (object_class, PROP_MODEL,
+         g_param_spec_object (NMN_PANEL_CLIENT_MODEL,
+                              "NMStatusModel",
+                              "NMStatusModel",
+                              NM_TYPE_STATUS_MODEL,
+                              G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+}
diff --git a/src/nmn-panel-client.h b/src/nmn-panel-client.h
new file mode 100644
index 0000000..875f73d
--- /dev/null
+++ b/src/nmn-panel-client.h
@@ -0,0 +1,52 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2009 Novell, Inc.
+ */
+
+#ifndef NMN_PANEL_CLIENT_H
+#define NMN_PANEL_CLIENT_H
+
+#include <glib-object.h>
+#include <moblin-panel/mpl-panel-gtk.h>
+#include <nm-status-model.h>
+
+G_BEGIN_DECLS
+
+#define NMN_TYPE_PANEL_CLIENT            (nmn_panel_client_get_type ())
+#define NMN_PANEL_CLIENT(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMN_TYPE_PANEL_CLIENT, NmnPanelClient))
+#define NMN_PANEL_CLIENT_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), NMN_TYPE_PANEL_CLIENT, NmnPanelClientClass))
+#define NMN_IS_PANEL_CLIENT(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMN_TYPE_PANEL_CLIENT))
+#define NMN_IS_PANEL_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NMN_TYPE_PANEL_CLIENT))
+#define NMN_PANEL_CLIENT_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NMN_TYPE_PANEL_CLIENT, NmnPanelClientClass))
+
+#define NMN_PANEL_CLIENT_MODEL "model"
+
+typedef struct {
+    MplPanelGtk parent;
+} NmnPanelClient;
+
+typedef struct {
+    MplPanelGtkClass parent;
+} NmnPanelClientClass;
+
+GType nmn_panel_client_get_type (void);
+
+NmnPanelClient *nmn_panel_client_new (NMStatusModel *model);
+
+G_END_DECLS
+
+#endif /* NMN_PANEL_CLIENT_H */
diff --git a/src/utils.c b/src/utils.c
index 575f94b..22bed05 100644
--- a/src/utils.c
+++ b/src/utils.c
@@ -1,832 +1,7 @@
 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
-/* NetworkManager Wireless Applet -- Display wireless access points and allow user control
- *
- * Dan Williams <dcbw redhat com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * (C) Copyright 2007 Red Hat, Inc.
- */
-
-#include <string.h>
-#include <netinet/ether.h>
-#include <glib.h>
 
 #include <moblin-panel/mpl-panel-client.h>
-#include <nm-device-ethernet.h>
-#include <nm-device-wifi.h>
-#include <nm-device-bt.h>
-#include <nm-gsm-device.h>
-#include <nm-cdma-device.h>
-#include <nm-access-point.h>
-#include <nm-setting-connection.h>
-#include <nm-setting-wired.h>
-#include <nm-setting-wireless.h>
-#include <nm-setting-wireless-security.h>
-#include <nm-setting-8021x.h>
-#include <nm-setting-gsm.h>
-#include <nm-setting-cdma.h>
-#include <nm-setting-pppoe.h>
-#include <nm-setting-bluetooth.h>
-#include <nm-utils.h>
-
 #include "utils.h"
-#include "gconf-helpers.h"
-
-/*
- * utils_bin2hexstr
- *
- * Convert a byte-array into a hexadecimal string.
- *
- * Code originally by Alex Larsson <alexl redhat com> and
- *  copyright Red Hat, Inc. under terms of the LGPL.
- *
- */
-char *
-utils_bin2hexstr (const char *bytes, int len, int final_len)
-{
-	static char	hex_digits[] = "0123456789abcdef";
-	char *		result;
-	int			i;
-
-	g_return_val_if_fail (bytes != NULL, NULL);
-	g_return_val_if_fail (len > 0, NULL);
-	g_return_val_if_fail (len < 256, NULL);	/* Arbitrary limit */
-
-	result = g_malloc0 (len * 2 + 1);
-	for (i = 0; i < len; i++)
-	{
-		result[2*i] = hex_digits[(bytes[i] >> 4) & 0xf];
-		result[2*i+1] = hex_digits[bytes[i] & 0xf];
-	}
-	/* Cut converted key off at the correct length for this cipher type */
-	if (final_len > -1)
-		result[final_len] = '\0';
-
-	return result;
-}
-
-static char *ignored_words[] = {
-	"Semiconductor",
-	"Components",
-	"Corporation",
-	"Communications",
-	"Company",
-	"Corp.",
-	"Corp",
-	"Co.",
-	"Inc.",
-	"Inc",
-	"Ltd.",
-	"Limited.",
-	"Intel?",
-	"chipset",
-	"adapter",
-	"[hex]",
-	"NDIS",
-	"Module",
-	NULL
-};
-
-static char *ignored_phrases[] = {
-	"Multiprotocol MAC/baseband processor",
-	"Wireless LAN Controller",
-	"Wireless LAN Adapter",
-	"Wireless Adapter",
-	"Network Connection",
-	"Wireless Cardbus Adapter",
-	"Wireless CardBus Adapter",
-	"54 Mbps Wireless PC Card",
-	"Wireless PC Card",
-	"Wireless PC",
-	"PC Card with XJACK(r) Antenna",
-	"Wireless cardbus",
-	"Wireless LAN PC Card",
-	"Technology Group Ltd.",
-	"Communication S.p.A.",
-	"Business Mobile Networks BV",
-	"Mobile Broadband Minicard Composite Device",
-	"Mobile Communications AB",
-	NULL
-};
-
-static char *
-fixup_desc_string (const char *desc)
-{
-	char *p, *temp;
-	char **words, **item;
-	GString *str;
-
-	p = temp = g_strdup (desc);
-	while (*p) {
-		if (*p == '_' || *p == ',')
-			*p = ' ';
-		p++;
-	}
-
-	/* Attempt to shorten ID by ignoring certain phrases */
-	for (item = ignored_phrases; *item; item++) {
-		guint32 ignored_len = strlen (*item);
-
-		p = strstr (temp, *item);
-		if (p)
-			memmove (p, p + ignored_len, strlen (p + ignored_len) + 1); /* +1 for the \0 */
-	}
-
-	/* Attmept to shorten ID by ignoring certain individual words */
-	words = g_strsplit (temp, " ", 0);
-	str = g_string_new_len (NULL, strlen (temp));
-	g_free (temp);
-
-	for (item = words; *item; item++) {
-		int i = 0;
-		gboolean ignore = FALSE;
-
-		if (g_ascii_isspace (**item) || (**item == '\0'))
-			continue;
-
-		while (ignored_words[i] && !ignore) {
-			if (!strcmp (*item, ignored_words[i]))
-				ignore = TRUE;
-			i++;
-		}
-
-		if (!ignore) {
-			if (str->len)
-				g_string_append_c (str, ' ');
-			g_string_append (str, *item);
-		}
-	}
-	g_strfreev (words);
-
-	temp = str->str;
-	g_string_free (str, FALSE);
-
-	return temp;
-}
-
-#define DESC_TAG "description"
-
-const char *
-utils_get_device_description (NMDevice *device)
-{
-	char *description = NULL;
-	const char *dev_product;
-	const char *dev_vendor;
-	char *product = NULL;
-	char *vendor = NULL;
-	GString *str;
-
-	g_return_val_if_fail (device != NULL, NULL);
-
-	description = g_object_get_data (G_OBJECT (device), DESC_TAG);
-	if (description)
-		return description;
-
-	dev_product = nm_device_get_product (device);
-	dev_vendor = nm_device_get_vendor (device);
-	if (!dev_product || !dev_vendor)
-		return NULL;
-
-	product = fixup_desc_string (dev_product);
-	vendor = fixup_desc_string (dev_vendor);
-
-	str = g_string_new_len (NULL, strlen (vendor) + strlen (product) + 1);
-
-	g_string_append (str, vendor);
-	g_free (vendor);
-
-	g_string_append_c (str, ' ');
-	g_string_append (str, product);
-	g_free (product);
-
-	description = str->str;
-	g_string_free (str, FALSE);
-
-	g_object_set_data_full (G_OBJECT (device),
-	                        "description", description,
-	                        (GDestroyNotify) g_free);
-
-	return description;
-}
-
-struct cf_pair {
-	guint32 chan;
-	guint32 freq;
-};
-
-static struct cf_pair a_table[] = {
-	/* A band */
-	{  7, 5035 },
-	{  8, 5040 },
-	{  9, 5045 },
-	{ 11, 5055 },
-	{ 12, 5060 },
-	{ 16, 5080 },
-	{ 34, 5170 },
-	{ 36, 5180 },
-	{ 38, 5190 },
-	{ 40, 5200 },
-	{ 42, 5210 },
-	{ 44, 5220 },
-	{ 46, 5230 },
-	{ 48, 5240 },
-	{ 50, 5250 },
-	{ 52, 5260 },
-	{ 56, 5280 },
-	{ 58, 5290 },
-	{ 60, 5300 },
-	{ 64, 5320 },
-	{ 100, 5500 },
-	{ 104, 5520 },
-	{ 108, 5540 },
-	{ 112, 5560 },
-	{ 116, 5580 },
-	{ 120, 5600 },
-	{ 124, 5620 },
-	{ 128, 5640 },
-	{ 132, 5660 },
-	{ 136, 5680 },
-	{ 140, 5700 },
-	{ 149, 5745 },
-	{ 152, 5760 },
-	{ 153, 5765 },
-	{ 157, 5785 },
-	{ 160, 5800 },
-	{ 161, 5805 },
-	{ 165, 5825 },
-	{ 183, 4915 },
-	{ 184, 4920 },
-	{ 185, 4925 },
-	{ 187, 4935 },
-	{ 188, 4945 },
-	{ 192, 4960 },
-	{ 196, 4980 },
-	{ 0, -1 }
-};
-
-static struct cf_pair bg_table[] = {
-	/* B/G band */
-	{ 1, 2412 },
-	{ 2, 2417 },
-	{ 3, 2422 },
-	{ 4, 2427 },
-	{ 5, 2432 },
-	{ 6, 2437 },
-	{ 7, 2442 },
-	{ 8, 2447 },
-	{ 9, 2452 },
-	{ 10, 2457 },
-	{ 11, 2462 },
-	{ 12, 2467 },
-	{ 13, 2472 },
-	{ 14, 2484 },
-	{ 0, -1 }
-};
-
-guint32
-utils_freq_to_channel (guint32 freq)
-{
-	int i = 0;
-
-	while (a_table[i].chan && (a_table[i].freq != freq))
-		i++;
-	if (a_table[i].chan)
-		return a_table[i].chan;
-
-	i = 0;
-	while (bg_table[i].chan && (bg_table[i].freq != freq))
-		i++;
-	return bg_table[i].chan;
-}
-
-guint32
-utils_channel_to_freq (guint32 channel, char *band)
-{
-	int i = 0;
-
-	if (!strcmp (band, "a")) {
-		while (a_table[i].chan && (a_table[i].chan != channel))
-			i++;
-		return a_table[i].freq;
-	} else if (!strcmp (band, "bg")) {
-		while (bg_table[i].chan && (bg_table[i].chan != channel))
-			i++;
-		return bg_table[i].freq;
-	}
-
-	return 0;
-}
-
-guint32
-utils_find_next_channel (guint32 channel, int direction, char *band)
-{
-	size_t a_size = sizeof (a_table) / sizeof (struct cf_pair);
-	size_t bg_size = sizeof (bg_table) / sizeof (struct cf_pair);
-	struct cf_pair *pair = NULL;
-
-	if (!strcmp (band, "a")) {
-		if (channel < a_table[0].chan)
-			return a_table[0].chan;
-		if (channel > a_table[a_size - 2].chan)
-			return a_table[a_size - 2].chan;
-		pair = &a_table[0];
-	} else if (!strcmp (band, "bg")) {
-		if (channel < bg_table[0].chan)
-			return bg_table[0].chan;
-		if (channel > bg_table[bg_size - 2].chan)
-			return bg_table[bg_size - 2].chan;
-		pair = &bg_table[0];
-	} else {
-		g_assert_not_reached ();
-		return 0;
-	}
-
-	while (pair->chan) {
-		if (channel == pair->chan)
-			return channel;
-		if ((channel < (pair+1)->chan) && (channel > pair->chan)) {
-			if (direction > 0)	
-				return (pair+1)->chan;
-			else
-				return pair->chan;
-		}
-		pair++;
-	}
-	return 0;
-}
-
-/*
- * utils_ether_addr_valid
- *
- * Compares an Ethernet address against known invalid addresses.
- *
- */
-gboolean
-utils_ether_addr_valid (const struct ether_addr *test_addr)
-{
-	guint8 invalid_addr1[ETH_ALEN] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
-	guint8 invalid_addr2[ETH_ALEN] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
-	guint8 invalid_addr3[ETH_ALEN] = {0x44, 0x44, 0x44, 0x44, 0x44, 0x44};
-	guint8 invalid_addr4[ETH_ALEN] = {0x00, 0x30, 0xb4, 0x00, 0x00, 0x00}; /* prism54 dummy MAC */
-
-	g_return_val_if_fail (test_addr != NULL, FALSE);
-
-	/* Compare the AP address the card has with invalid ethernet MAC addresses. */
-	if (!memcmp (test_addr->ether_addr_octet, &invalid_addr1, ETH_ALEN))
-		return FALSE;
-
-	if (!memcmp (test_addr->ether_addr_octet, &invalid_addr2, ETH_ALEN))
-		return FALSE;
-
-	if (!memcmp (test_addr->ether_addr_octet, &invalid_addr3, ETH_ALEN))
-		return FALSE;
-
-	if (!memcmp (test_addr->ether_addr_octet, &invalid_addr4, ETH_ALEN))
-		return FALSE;
-
-	if (test_addr->ether_addr_octet[0] & 1)			/* Multicast addresses */
-		return FALSE;
-	
-	return TRUE;
-}
-
-static gboolean
-utils_check_ap_compatible (NMAccessPoint *ap,
-                           NMConnection *connection)
-{
-	NMSettingWireless *s_wireless;
-	NMSettingWirelessSecurity *s_wireless_sec;
-	const GByteArray *setting_bssid;
-	const char *setting_mode;
-	const char *setting_band;
-	NM80211Mode ap_mode;
-	guint32 freq;
-
-	g_return_val_if_fail (NM_IS_ACCESS_POINT (ap), FALSE);
-	g_return_val_if_fail (NM_IS_CONNECTION (connection), FALSE);
-
-	s_wireless = NM_SETTING_WIRELESS (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS));
-	if (s_wireless == NULL)
-		return FALSE;
-	
-	if (!nm_utils_same_ssid (nm_setting_wireless_get_ssid (s_wireless), nm_access_point_get_ssid (ap), TRUE))
-		return FALSE;
-
-	setting_bssid = nm_setting_wireless_get_bssid (s_wireless);
-	if (setting_bssid) {
-		struct ether_addr ap_addr;
-
-		if (ether_aton_r (nm_access_point_get_hw_address (ap), &ap_addr)) {
-			if (memcmp (setting_bssid->data, &ap_addr, ETH_ALEN))
-				return FALSE;
-		}
-	}
-
-	ap_mode = nm_access_point_get_mode (ap);
-	setting_mode = nm_setting_wireless_get_mode (s_wireless);
-	if (setting_mode) {
-		if (   !strcmp (setting_mode, "infrastructure")
-		    && (ap_mode != NM_802_11_MODE_INFRA))
-			return FALSE;
-		if (   !strcmp (setting_mode, "adhoc")
-		    && (ap_mode != NM_802_11_MODE_ADHOC))
-			return FALSE;
-	}
-
-	freq = nm_access_point_get_frequency (ap);
-	setting_band = nm_setting_wireless_get_band (s_wireless);
-	if (setting_band) {
-		if (!strcmp (setting_band, "a")) {
-			if (freq < 5170 || freq > 5825)
-				return FALSE;
-		} else if (!strcmp (setting_band, "bg")) {
-			if (freq < 2412 || freq > 2472)
-				return FALSE;
-		}
-	}
-
-	// FIXME: channel check
-
-	s_wireless_sec = (NMSettingWirelessSecurity *) nm_connection_get_setting (connection,
-															    NM_TYPE_SETTING_WIRELESS_SECURITY);
-
-	return nm_setting_wireless_ap_security_compatible (s_wireless,
-											 s_wireless_sec,
-											 nm_access_point_get_flags (ap),
-											 nm_access_point_get_wpa_flags (ap),
-											 nm_access_point_get_rsn_flags (ap),
-											 nm_access_point_get_mode (ap));
-}
-
-static gboolean
-connection_valid_for_wired (NMConnection *connection,
-                            NMSettingConnection *s_con,
-                            NMDevice *device,
-                            gpointer specific_object)
-{
-	NMDeviceEthernet *ethdev = NM_DEVICE_ETHERNET (device);
-	NMSettingWired *s_wired;
-	const char *str_mac;
-	struct ether_addr *bin_mac;
-	const char *connection_type;
-	const GByteArray *setting_mac;
-	gboolean is_pppoe = FALSE;
-
-	connection_type = nm_setting_connection_get_connection_type (s_con);
-	if (!strcmp (connection_type, NM_SETTING_PPPOE_SETTING_NAME))
-		is_pppoe = TRUE;
-	
-	if (!is_pppoe && strcmp (connection_type, NM_SETTING_WIRED_SETTING_NAME))
-		return FALSE;
-
-	s_wired = NM_SETTING_WIRED (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRED));
-	if (!is_pppoe && !s_wired)
-		return FALSE;
-
-	if (s_wired) {
-		/* Match MAC address */
-		setting_mac = nm_setting_wired_get_mac_address (s_wired);
-		if (!setting_mac)
-			return TRUE;
-
-		str_mac = nm_device_ethernet_get_hw_address (ethdev);
-		g_return_val_if_fail (str_mac != NULL, FALSE);
-
-		bin_mac = ether_aton (str_mac);
-		g_return_val_if_fail (bin_mac != NULL, FALSE);
-
-		if (memcmp (bin_mac->ether_addr_octet, setting_mac->data, ETH_ALEN))
-			return FALSE;
-	}
-
-	return TRUE;
-}
-
-static gboolean
-connection_valid_for_wireless (NMConnection *connection,
-                               NMSettingConnection *s_con,
-                               NMDevice *device,
-                               gpointer specific_object)
-{
-	NMDeviceWifi *wdev = NM_DEVICE_WIFI (device);
-	NMSettingWireless *s_wireless;
-	NMSettingWirelessSecurity *s_wireless_sec;
-	const GByteArray *setting_mac;
-	const char *setting_security, *key_mgmt;
-	guint32 wcaps;
-	NMAccessPoint *ap;
-
-	if (strcmp (nm_setting_connection_get_connection_type (s_con), NM_SETTING_WIRELESS_SETTING_NAME))
-		return FALSE;
-
-	s_wireless = NM_SETTING_WIRELESS (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS));
-	g_return_val_if_fail (s_wireless != NULL, FALSE);
-
-	/* Match MAC address */
-	setting_mac = nm_setting_wireless_get_mac_address (s_wireless);
-	if (setting_mac) {
-		const char *str_mac;
-		struct ether_addr *bin_mac;
-
-		str_mac = nm_device_wifi_get_hw_address (wdev);
-		g_return_val_if_fail (str_mac != NULL, FALSE);
-
-		bin_mac = ether_aton (str_mac);
-		g_return_val_if_fail (bin_mac != NULL, FALSE);
-
-		if (memcmp (bin_mac->ether_addr_octet, setting_mac->data, ETH_ALEN))
-			return FALSE;
-	}
-
-	/* If an AP was given make sure that's compatible with the connection first */
-	if (specific_object) {
-		ap = NM_ACCESS_POINT (specific_object);
-		g_assert (ap);
-
-		if (!utils_check_ap_compatible (ap, connection))
-			return FALSE;
-	}
-
-	setting_security = nm_setting_wireless_get_security (s_wireless);
-	if (!setting_security || strcmp (setting_security, NM_SETTING_WIRELESS_SECURITY_SETTING_NAME))
-		return TRUE; /* all devices can do unencrypted networks */
-
-	s_wireless_sec = NM_SETTING_WIRELESS_SECURITY (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS_SECURITY));
-	if (!s_wireless_sec)
-		return TRUE; /* all devices can do unencrypted networks */
-
-	key_mgmt = nm_setting_wireless_security_get_key_mgmt (s_wireless_sec);
-
-	/* All devices should support static WEP */
-	if (!strcmp (key_mgmt, "none"))
-		return TRUE;
-
-	/* All devices should support legacy LEAP and Dynamic WEP */
-	if (!strcmp (key_mgmt, "ieee8021x"))
-		return TRUE;
-
-	/* Match security with device capabilities */
-	wcaps = nm_device_wifi_get_capabilities (wdev);
-
-	/* At this point, the device better have basic WPA support. */
-	if (   !(wcaps & NM_WIFI_DEVICE_CAP_WPA)
-	    || !(wcaps & NM_WIFI_DEVICE_CAP_CIPHER_TKIP))
-		return FALSE;
-
-	/* Check for only RSN */
-	if (   (nm_setting_wireless_security_get_num_protos (s_wireless_sec) == 1)
-	    && !strcmp (nm_setting_wireless_security_get_proto (s_wireless_sec, 0), "rsn")
-	    && !(wcaps & NM_WIFI_DEVICE_CAP_RSN))
-		return FALSE;
-
-	/* Check for only pairwise CCMP */
-	if (   (nm_setting_wireless_security_get_num_pairwise (s_wireless_sec) == 1)
-	    && !strcmp (nm_setting_wireless_security_get_pairwise (s_wireless_sec, 0), "ccmp")
-	    && !(wcaps & NM_WIFI_DEVICE_CAP_CIPHER_CCMP))
-		return FALSE;
-
-	/* Check for only group CCMP */
-	if (   (nm_setting_wireless_security_get_num_groups (s_wireless_sec) == 1)
-	    && !strcmp (nm_setting_wireless_security_get_group (s_wireless_sec, 0), "ccmp")
-	    && !(wcaps & NM_WIFI_DEVICE_CAP_CIPHER_CCMP))
-		return FALSE;
-
-	return TRUE;
-}
-
-static gboolean
-connection_valid_for_gsm (NMConnection *connection,
-                          NMSettingConnection *s_con,
-                          NMDevice *device,
-                          gpointer specific_object)
-{
-	NMSettingGsm *s_gsm;
-	
-	if (strcmp (nm_setting_connection_get_connection_type (s_con), NM_SETTING_GSM_SETTING_NAME))
-		return FALSE;
-
-	s_gsm = NM_SETTING_GSM (nm_connection_get_setting (connection, NM_TYPE_SETTING_GSM));
-	g_return_val_if_fail (s_gsm != NULL, FALSE);
-
-	return TRUE;
-}
-
-static gboolean
-connection_valid_for_cdma (NMConnection *connection,
-                           NMSettingConnection *s_con,
-                           NMDevice *device,
-                           gpointer specific_object)
-{
-	NMSettingCdma *s_cdma;
-	
-	if (strcmp (nm_setting_connection_get_connection_type (s_con), NM_SETTING_CDMA_SETTING_NAME))
-		return FALSE;
-
-	s_cdma = NM_SETTING_CDMA (nm_connection_get_setting (connection, NM_TYPE_SETTING_CDMA));
-	g_return_val_if_fail (s_cdma != NULL, FALSE);
-
-	return TRUE;
-}
-
-static guint32
-get_connection_bt_type (NMConnection *connection)
-{
-	NMSettingBluetooth *s_bt;
-	const char *bt_type;
-
-	s_bt = (NMSettingBluetooth *) nm_connection_get_setting (connection, NM_TYPE_SETTING_BLUETOOTH);
-	if (!s_bt)
-		return NM_BT_CAPABILITY_NONE;
-
-	bt_type = nm_setting_bluetooth_get_connection_type (s_bt);
-	g_assert (bt_type);
-
-	if (!strcmp (bt_type, NM_SETTING_BLUETOOTH_TYPE_DUN))
-		return NM_BT_CAPABILITY_DUN;
-	else if (!strcmp (bt_type, NM_SETTING_BLUETOOTH_TYPE_PANU))
-		return NM_BT_CAPABILITY_NAP;
-
-	return NM_BT_CAPABILITY_NONE;
-}
-
-static gboolean
-connection_valid_for_bt (NMConnection *connection,
-                         NMSettingConnection *s_con,
-                         NMDevice *device,
-                         gpointer specific_object)
-{
-	NMSettingBluetooth *s_bt;
-	const GByteArray *array;
-	char *str;
-	const char *hw_addr;
-	int addr_match = FALSE;
-	guint32 bt_type;
-
-	if (strcmp (nm_setting_connection_get_connection_type (s_con), NM_SETTING_BLUETOOTH_SETTING_NAME))
-		return FALSE;
-
-	s_bt = NM_SETTING_BLUETOOTH (nm_connection_get_setting (connection, NM_TYPE_SETTING_BLUETOOTH));
-	if (!s_bt)
-		return FALSE;
-
-	array = nm_setting_bluetooth_get_bdaddr (s_bt);
-	if (!array || (array->len != ETH_ALEN))
-		return FALSE;
-
-	bt_type = get_connection_bt_type (connection);
-	if (!(bt_type & nm_device_bt_get_capabilities (NM_DEVICE_BT (device))))
-		return FALSE;
-
-	str = g_strdup_printf ("%02X:%02X:%02X:%02X:%02X:%02X",
-	                       array->data[0], array->data[1], array->data[2],
-	                       array->data[3], array->data[4], array->data[5]);
-	hw_addr = nm_device_bt_get_hw_address (NM_DEVICE_BT (device));
-	if (hw_addr)
-		addr_match = !g_ascii_strcasecmp (hw_addr, str);
-	g_free (str);
-
-	return addr_match;
-}
-
-gboolean
-utils_connection_valid_for_device (NMConnection *connection,
-                                   NMDevice *device,
-                                   gpointer specific_object)
-{
-	NMSettingConnection *s_con;
-
-	g_return_val_if_fail (connection != NULL, FALSE);
-	g_return_val_if_fail (device != NULL, FALSE);
-
-	s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION));
-	g_return_val_if_fail (s_con != NULL, FALSE);
-	g_return_val_if_fail (nm_setting_connection_get_connection_type (s_con) != NULL, FALSE);
-
-	if (NM_IS_DEVICE_ETHERNET (device))
-		return connection_valid_for_wired (connection, s_con, device, specific_object);
-	else if (NM_IS_DEVICE_WIFI (device))
-		return connection_valid_for_wireless (connection, s_con, device, specific_object);
-	else if (NM_IS_GSM_DEVICE (device))
-		return connection_valid_for_gsm (connection, s_con, device, specific_object);
-	else if (NM_IS_CDMA_DEVICE (device))
-		return connection_valid_for_cdma (connection, s_con, device, specific_object);
-	else if (NM_IS_DEVICE_BT (device))
-		return connection_valid_for_bt (connection, s_con, device, specific_object);
-	else
-		g_warning ("Unknown device type '%s'", g_type_name (G_OBJECT_TYPE(device)));
-
-	return FALSE;
-}
-
-GSList *
-utils_filter_connections_for_device (NMDevice *device, GSList *connections)
-{
-	GSList *iter;
-	GSList *filtered = NULL;
-
-	for (iter = connections; iter; iter = g_slist_next (iter)) {
-		NMConnection *connection = NM_CONNECTION (iter->data);
-
-		if (utils_connection_valid_for_device (connection, device, NULL))
-			filtered = g_slist_append (filtered, connection);
-	}
-
-	return filtered;
-}
-
-gboolean
-utils_mac_valid (const struct ether_addr *addr)
-{
-	guint8 invalid1[ETH_ALEN] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
-	guint8 invalid2[ETH_ALEN] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
-	guint8 invalid3[ETH_ALEN] = {0x44, 0x44, 0x44, 0x44, 0x44, 0x44};
-	guint8 invalid4[ETH_ALEN] = {0x00, 0x30, 0xb4, 0x00, 0x00, 0x00}; /* prism54 dummy MAC */
-
-	g_return_val_if_fail (addr != NULL, FALSE);
-
-	/* Compare the AP address the card has with invalid ethernet MAC addresses. */
-	if (!memcmp (addr->ether_addr_octet, &invalid1, ETH_ALEN))
-		return FALSE;
-
-	if (!memcmp (addr->ether_addr_octet, &invalid2, ETH_ALEN))
-		return FALSE;
-
-	if (!memcmp (addr->ether_addr_octet, &invalid3, ETH_ALEN))
-		return FALSE;
-
-	if (!memcmp (addr->ether_addr_octet, &invalid4, ETH_ALEN))
-		return FALSE;
-
-	if (addr->ether_addr_octet[0] & 1) /* Multicast addresses */
-		return FALSE;
-	
-	return TRUE;
-}
-
-char *
-utils_ether_ntop (const struct ether_addr *mac)
-{
-	/* we like leading zeros and all-caps, instead
-	 * of what glibc's ether_ntop() gives us
-	 */
-	return g_strdup_printf ("%02X:%02X:%02X:%02X:%02X:%02X",
-	                        mac->ether_addr_octet[0], mac->ether_addr_octet[1],
-	                        mac->ether_addr_octet[2], mac->ether_addr_octet[3],
-	                        mac->ether_addr_octet[4], mac->ether_addr_octet[5]);
-}
-
-char *
-utils_next_available_name (GSList *connections, const char *format)
-{
-	GSList *names = NULL, *iter;
-	char *cname = NULL;
-	int i = 0;
-
-	for (iter = connections; iter; iter = g_slist_next (iter)) {
-		NMConnection *candidate = NM_CONNECTION (iter->data);
-		NMSettingConnection *s_con;
-		const char *id;
-
-		s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (candidate, NM_TYPE_SETTING_CONNECTION));
-		id = nm_setting_connection_get_id (s_con);
-		g_assert (id);
-		names = g_slist_append (names, (gpointer) id);
-	}	
-
-	/* Find the next available unique connection name */
-	while (!cname && (i++ < 10000)) {
-		char *temp;
-		gboolean found = FALSE;
-
-		temp = g_strdup_printf (format, i);
-		for (iter = names; iter; iter = g_slist_next (iter)) {
-			if (!strcmp (iter->data, temp)) {
-				found = TRUE;
-				break;
-			}
-		}
-		if (!found)
-			cname = temp;
-		else
-			g_free (temp);
-	}
-
-	g_slist_free (names);
-	return cname;
-}
 
 static MplPanelClient *main_widget = NULL;
 
diff --git a/src/utils.h b/src/utils.h
index d4dd553..e6cce21 100644
--- a/src/utils.h
+++ b/src/utils.h
@@ -1,59 +1,13 @@
-/* NetworkManager Wireless Applet -- Display wireless access points and allow user control
- *
- * Dan Williams <dcbw redhat com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * (C) Copyright 2007 Red Hat, Inc.
- */
+/* NetworkManager Wireless Applet -- Display wireless access points and allow user control */
 
-#ifndef UTILS_H
-#define UTILS_H
+#ifndef HACK_H
+#define HACK_H
 
-#include <glib.h>
-#include <gtk/gtk.h>
-#include <nm-connection.h>
-#include <nm-device.h>
-#include <net/ethernet.h>
-#include <nm-access-point.h>
-
-char * utils_bin2hexstr (const char *bytes, int len, int final_len);
-
-const char *utils_get_device_description (NMDevice *device);
-
-guint32 utils_freq_to_channel (guint32 freq);
-guint32 utils_channel_to_freq (guint32 channel, char *band);
-guint32 utils_find_next_channel (guint32 channel, int direction, char *band);
-
-gboolean utils_ether_addr_valid (const struct ether_addr *test_addr);
-
-gboolean utils_connection_valid_for_device (NMConnection *connection,
-                                            NMDevice *device,
-                                            gpointer specific_object);
-
-GSList *utils_filter_connections_for_device (NMDevice *device, GSList *connections);
-
-char *utils_ether_ntop (const struct ether_addr *mac);
-
-gboolean utils_mac_valid (const struct ether_addr *addr);
-
-char *utils_next_available_name (GSList *connections, const char *format);
+#include <glib-object.h>
 
 /* Ugh, please avert your eyes... */
 void utils_set_main_widget (GObject *panel_client);
 void utils_hide_main_widget (void);
 
-#endif /* UTILS_H */
+#endif /* HACK_H */
 



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