public inbox for gentoo-commits@lists.gentoo.org
 help / color / mirror / Atom feed
* [gentoo-commits] proj/gnome:master commit in: dev-libs/gobject-introspection/files/, gnome-base/gnome-shell/, ...
@ 2011-02-20 23:19 Nirbheek Chauhan
  0 siblings, 0 replies; only message in thread
From: Nirbheek Chauhan @ 2011-02-20 23:19 UTC (permalink / raw
  To: gentoo-commits

commit:     d4ba6cfc87017fa637354a579668a0fce509a996
Author:     Nirbheek Chauhan <nirbheek <AT> gentoo <DOT> org>
AuthorDate: Sun Feb 20 21:39:00 2011 +0000
Commit:     Nirbheek Chauhan <nirbheek <AT> gentoo <DOT> org>
CommitDate: Sun Feb 20 23:12:52 2011 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/gnome.git;a=commit;h=d4ba6cfc

gnome-base/gnome-shell: experimental networkmanager applet

* The applet is tracked at: https://bugzilla.gnome.org/show_bug.cgi?id=621707
* Needs a patch to gobject-introspection to fix:
  https://bugzilla.gnome.org/show_bug.cgi?id=642300
  - The patch was added to overlay so that it gets some testing
* Needs NetworkManager trunk with the latest patch from:
  https://bugzilla.gnome.org/show_bug.cgi?id=637032
* Needs nm-applet for secrets and wireless dialogs

---
 ...on-0.10.2-fix-lookup-of-cached-type-nodes.patch |   82 +
 .../gobject-introspection-0.10.2-r1.ebuild         |   62 +
 .../gnome-shell/files/gnome-shell-nm-1.patch       |  124 ++
 .../gnome-shell/files/gnome-shell-nm-2.patch       |  165 ++
 .../gnome-shell/files/gnome-shell-nm-3.patch       | 1868 ++++++++++++++++++++
 gnome-base/gnome-shell/gnome-shell-9999.ebuild     |   23 +-
 .../files/networkmanager-introspection-fixes.patch |  206 +++
 net-misc/networkmanager/metadata.xml               |   24 +
 net-misc/networkmanager/networkmanager-9999.ebuild |   13 +-
 9 files changed, 2560 insertions(+), 7 deletions(-)

diff --git a/dev-libs/gobject-introspection/files/gobject-introspection-0.10.2-fix-lookup-of-cached-type-nodes.patch b/dev-libs/gobject-introspection/files/gobject-introspection-0.10.2-fix-lookup-of-cached-type-nodes.patch
new file mode 100644
index 0000000..b828a12
--- /dev/null
+++ b/dev-libs/gobject-introspection/files/gobject-introspection-0.10.2-fix-lookup-of-cached-type-nodes.patch
@@ -0,0 +1,82 @@
+From 7829831776c921891122d29e2461fbc1f11f71f1 Mon Sep 17 00:00:00 2001
+From: Giovanni Campagna <gcampagna@src.gnome.org>
+Date: Fri, 18 Feb 2011 18:14:25 +0100
+Subject: [PATCH] GIrNode: fix lookup of cached type nodes
+
+Different types of array have different type nodes, so they should
+produce different keys in the cache of already seen type nodes, to
+avoid turning a GByteArray into a reference to a GPtrArray.
+
+https://bugzilla.gnome.org/show_bug.cgi?id=642300
+---
+ girepository/girnode.c |   45 ++++++++++++++++++++++++++++++++++-----------
+ 1 files changed, 34 insertions(+), 11 deletions(-)
+
+diff --git a/girepository/girnode.c b/girepository/girnode.c
+index fe45503..fe10e54 100644
+--- a/girepository/girnode.c
++++ b/girepository/girnode.c
+@@ -1227,19 +1227,42 @@ serialize_type (GIrTypelibBuild    *build,
+     }
+   else if (node->tag == GI_TYPE_TAG_ARRAY)
+     {
+-      serialize_type (build, node->parameter_type1, str);
+-      g_string_append (str, "[");
++      if (node->array_type == GI_ARRAY_TYPE_C)
++	{
++	  serialize_type (build, node->parameter_type1, str);
++	  g_string_append (str, "[");
+ 
+-      if (node->has_length)
+-	g_string_append_printf (str, "length=%d", node->length);
+-      else if (node->has_size)
+-        g_string_append_printf (str, "fixed-size=%d", node->size);
++	  if (node->has_length)
++	    g_string_append_printf (str, "length=%d", node->length);
++	  else if (node->has_size)
++	    g_string_append_printf (str, "fixed-size=%d", node->size);
+ 
+-      if (node->zero_terminated)
+-	g_string_append_printf (str, "%szero-terminated=1",
+-				node->has_length ? "," : "");
++	  if (node->zero_terminated)
++	    g_string_append_printf (str, "%szero-terminated=1",
++				    node->has_length ? "," : "");
+ 
+-      g_string_append (str, "]");
++	  g_string_append (str, "]");
++	}
++      else if (node->array_type == GI_ARRAY_TYPE_BYTE_ARRAY)
++	{
++	  /* We on purpose skip serializing parameter_type1, which should
++	     always be void*
++	  */
++	  g_string_append (str, "GByteArray");
++	}
++      else
++	{
++	  if (node->array_type == GI_ARRAY_TYPE_ARRAY)
++	    g_string_append (str, "GArray");
++	  else
++	    g_string_append (str, "GPtrArray");
++	  if (node->parameter_type1)
++	    {
++	      g_string_append (str, "<");
++	      serialize_type (build, node->parameter_type1, str);
++	      g_string_append (str, ">");
++	    }
++	}
+     }
+   else if (node->tag == GI_TYPE_TAG_INTERFACE)
+     {
+@@ -1284,7 +1307,7 @@ serialize_type (GIrTypelibBuild    *build,
+     }
+   else if (node->tag == GI_TYPE_TAG_GHASH)
+     {
+-      g_string_append (str, "GHashTable<");
++      g_string_append (str, "GHashTable");
+       if (node->parameter_type1)
+ 	{
+ 	  g_string_append (str, "<");
+-- 
+1.7.4
\ No newline at end of file

diff --git a/dev-libs/gobject-introspection/gobject-introspection-0.10.2-r1.ebuild b/dev-libs/gobject-introspection/gobject-introspection-0.10.2-r1.ebuild
new file mode 100644
index 0000000..7d016d5
--- /dev/null
+++ b/dev-libs/gobject-introspection/gobject-introspection-0.10.2-r1.ebuild
@@ -0,0 +1,62 @@
+# Copyright 1999-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+# $Header: /var/cvsroot/gentoo-x86/dev-libs/gobject-introspection/gobject-introspection-0.10.2.ebuild,v 1.1 2011/02/08 09:54:03 pacho Exp $
+
+EAPI="3"
+GCONF_DEBUG="no"
+PYTHON_DEPEND="2:2.5"
+
+inherit eutils gnome2 python
+
+DESCRIPTION="Introspection infrastructure for gobject library bindings"
+HOMEPAGE="http://live.gnome.org/GObjectIntrospection/"
+
+LICENSE="LGPL-2 GPL-2"
+SLOT="0"
+KEYWORDS="~alpha ~amd64 ~arm ~ia64 ~ppc ~ppc64 ~s390 ~sh ~sparc ~x86"
+IUSE="doc test"
+
+RDEPEND=">=dev-libs/glib-2.24:2
+	virtual/libffi"
+DEPEND="${RDEPEND}
+	dev-util/pkgconfig
+	sys-devel/flex
+	doc? ( >=dev-util/gtk-doc-1.12 )
+	test? ( x11-libs/cairo )"
+
+pkg_setup() {
+	DOCS="AUTHORS CONTRIBUTORS ChangeLog NEWS README TODO"
+	G2CONF="${G2CONF}
+		--disable-static
+		$(use_enable test tests)"
+
+	python_set_active_version 2
+}
+
+src_prepare() {
+	# FIXME: Parallel compilation failure with USE=doc
+	use doc && MAKEOPTS="-j1"
+
+	# Don't pre-compile .py
+	ln -sf $(type -P true) py-compile
+
+	# Fix https://bugzilla.gnome.org/show_bug.cgi?id=642300
+	# causes problems with binding NMConnection from latest NM trunk
+	epatch "${FILESDIR}/${P}-fix-lookup-of-cached-type-nodes.patch"
+}
+
+src_install() {
+	gnome2_src_install
+	python_convert_shebangs 2 "${ED}"usr/bin/g-ir-scanner
+	python_convert_shebangs 2 "${ED}"usr/bin/g-ir-annotation-tool
+	find "${ED}" -name "*.la" -delete || die "la files removal failed"
+}
+
+pkg_postinst() {
+	python_mod_optimize /usr/$(get_libdir)/${PN}/giscanner
+	python_need_rebuild
+}
+
+pkg_postrm() {
+	python_mod_cleanup /usr/lib*/${PN}/giscanner
+}

diff --git a/gnome-base/gnome-shell/files/gnome-shell-nm-1.patch b/gnome-base/gnome-shell/files/gnome-shell-nm-1.patch
new file mode 100644
index 0000000..4a7580d
--- /dev/null
+++ b/gnome-base/gnome-shell/files/gnome-shell-nm-1.patch
@@ -0,0 +1,124 @@
+From 25884b4b480c18dae05f45e6739241d3e11cd12f Mon Sep 17 00:00:00 2001
+From: Giovanni Campagna <gcampagna@src.gnome.org>
+Date: Tue, 25 Jan 2011 22:06:40 +0100
+Subject: [PATCH] PopupMenu: make parameters overridable in items
+
+Make all subclasses of PopupMenuBase accept a params argument, which
+can be used to make the item non reactive, not responsive to hover
+and, as a new feature, with a different style class.
+
+https://bugzilla.gnome.org/show_bug.cgi?id=621707
+---
+ data/theme/gnome-shell.css |    4 ++++
+ js/ui/popupMenu.js         |   28 +++++++++++++++++++---------
+ js/ui/statusMenu.js        |    4 ++--
+ 3 files changed, 25 insertions(+), 11 deletions(-)
+
+diff --git a/data/theme/gnome-shell.css b/data/theme/gnome-shell.css
+index ba931ad..7bf17d4 100644
+--- a/data/theme/gnome-shell.css
++++ b/data/theme/gnome-shell.css
+@@ -178,6 +178,10 @@ StTooltip StLabel {
+     background-image: url("toggle-on-intl.svg");
+ }
+ 
++.popup-inactive-menu-item {
++	font-style: italic;
++}
++
+ /* Panel */
+ 
+ #panel {
+diff --git a/js/ui/popupMenu.js b/js/ui/popupMenu.js
+index 30f353e..4e88a2a 100644
+--- a/js/ui/popupMenu.js
++++ b/js/ui/popupMenu.js
+@@ -55,7 +55,9 @@ PopupBaseMenuItem.prototype = {
+     _init: function (params) {
+         params = Params.parse (params, { reactive: true,
+                                          activate: true,
+-                                         hover: true });
++                                         hover: true,
++                                         style_class: null
++                                       });
+         this.actor = new Shell.GenericContainer({ style_class: 'popup-menu-item',
+                                                   reactive: params.reactive,
+                                                   track_hover: params.reactive,
+@@ -72,6 +74,9 @@ PopupBaseMenuItem.prototype = {
+         this._spacing = 0;
+         this.active = false;
+ 
++        if (params.style_class)
++            this.actor.add_style_class_name(params.style_class);
++
+         if (params.reactive && params.activate) {
+             this.actor.connect('button-release-event', Lang.bind(this, this._onButtonReleaseEvent));
+             this.actor.connect('key-press-event', Lang.bind(this, this._onKeyPressEvent));
+@@ -533,8 +538,8 @@ function PopupSwitchMenuItem() {
+ PopupSwitchMenuItem.prototype = {
+     __proto__: PopupBaseMenuItem.prototype,
+ 
+-    _init: function(text, active) {
+-        PopupBaseMenuItem.prototype._init.call(this);
++    _init: function(text, active, params) {
++        PopupBaseMenuItem.prototype._init.call(this, params);
+ 
+         this.label = new St.Label({ text: text });
+         this._switch = new Switch(active);
+@@ -562,15 +567,15 @@ PopupSwitchMenuItem.prototype = {
+ }
+ 
+ 
+-function PopupImageMenuItem(text, iconName) {
+-    this._init(text, iconName);
++function PopupImageMenuItem() {
++    this._init.apply(this, arguments);
+ }
+ 
+ PopupImageMenuItem.prototype = {
+     __proto__: PopupBaseMenuItem.prototype,
+ 
+-    _init: function (text, iconName) {
+-        PopupBaseMenuItem.prototype._init.call(this);
++    _init: function (text, iconName, params) {
++        PopupBaseMenuItem.prototype._init.call(this, params);
+ 
+         this.label = new St.Label({ text: text });
+         this.addActor(this.label);
+@@ -615,8 +620,13 @@ PopupMenuBase.prototype = {
+     _init: function(sourceActor, styleClass) {
+         this.sourceActor = sourceActor;
+ 
+-        this.box = new St.BoxLayout({ style_class: styleClass,
+-                                      vertical: true });
++        // GJS bug: it complains when an optional property is undefined
++        if (styleClass !== undefined) {
++            this.box = new St.BoxLayout({ style_class: styleClass,
++                                          vertical: true });
++        } else {
++            this.box = new St.BoxLayout({ vertical: true });
++        }
+ 
+         this.isOpen = false;
+         this._activeMenuItem = null;
+diff --git a/js/ui/statusMenu.js b/js/ui/statusMenu.js
+index f834aad..9ca5692 100644
+--- a/js/ui/statusMenu.js
++++ b/js/ui/statusMenu.js
+@@ -99,12 +99,12 @@ StatusMenuButton.prototype = {
+     _createSubMenu: function() {
+         let item;
+ 
+-        item = new PopupMenu.PopupImageMenuItem(_("Available"), 'user-available', true);
++        item = new PopupMenu.PopupImageMenuItem(_("Available"), 'user-available');
+         item.connect('activate', Lang.bind(this, this._setPresenceStatus, GnomeSession.PresenceStatus.AVAILABLE));
+         this.menu.addMenuItem(item);
+         this._presenceItems[GnomeSession.PresenceStatus.AVAILABLE] = item;
+ 
+-        item = new PopupMenu.PopupImageMenuItem(_("Busy"), 'user-busy', true);
++        item = new PopupMenu.PopupImageMenuItem(_("Busy"), 'user-busy');
+         item.connect('activate', Lang.bind(this, this._setPresenceStatus, GnomeSession.PresenceStatus.BUSY));
+         this.menu.addMenuItem(item);
+         this._presenceItems[GnomeSession.PresenceStatus.BUSY] = item;
+-- 
+1.7.3.5
\ No newline at end of file

diff --git a/gnome-base/gnome-shell/files/gnome-shell-nm-2.patch b/gnome-base/gnome-shell/files/gnome-shell-nm-2.patch
new file mode 100644
index 0000000..e711763
--- /dev/null
+++ b/gnome-base/gnome-shell/files/gnome-shell-nm-2.patch
@@ -0,0 +1,165 @@
+From fa144c1aa5126097f28d54b91edf488b74b68f79 Mon Sep 17 00:00:00 2001
+From: Giovanni Campagna <gcampagna@src.gnome.org>
+Date: Tue, 25 Jan 2011 22:04:57 +0100
+Subject: [PATCH] PopupMenu: introduce PopupMenuSection
+
+Complex popup menus require the ability to manager sequences of items
+as "sections", to which you can add and and remove items, as well
+as hide and show.
+PopupMenuSection does exactly that, leveraging the existing machinery
+for submenus, but without being exposed as a submenu to the user.
+
+https://bugzilla.gnome.org/show_bug.cgi?id=621707
+---
+ js/ui/popupMenu.js |  115 +++++++++++++++++++++++++++++++++++++---------------
+ 1 files changed, 82 insertions(+), 33 deletions(-)
+
+diff --git a/js/ui/popupMenu.js b/js/ui/popupMenu.js
+index 4e88a2a..8615c87 100644
+--- a/js/ui/popupMenu.js
++++ b/js/ui/popupMenu.js
+@@ -640,38 +640,20 @@ PopupMenuBase.prototype = {
+         }));
+     },
+ 
+-    addMenuItem: function(menuItem, position) {
+-        let before_item = null;
+-        if (position == undefined) {
+-            this.box.add(menuItem.actor);
+-        } else {
+-            let items = this.getMenuItems();
+-            if (position < items.length) {
+-                before_item = items[position].actor;
+-                this.box.insert_before(menuItem.actor, before_item);
+-            } else
+-                this.box.add(menuItem.actor);
+-        }
+-        if (menuItem instanceof PopupSubMenuMenuItem) {
+-            if (before_item == null)
+-                this.box.add(menuItem.menu.actor);
+-            else
+-                this.box.insert_before(menuItem.menu.actor, before_item);
+-            menuItem._subMenuActivateId = menuItem.menu.connect('activate', Lang.bind(this, function() {
+-                this.emit('activate');
+-                this.close(true);
+-            }));
+-            menuItem._subMenuActiveChangeId = menuItem.menu.connect('active-changed', Lang.bind(this, function(submenu, submenuItem) {
+-                if (this._activeMenuItem && this._activeMenuItem != submenuItem)
+-                    this._activeMenuItem.setActive(false);
+-                this._activeMenuItem = submenuItem;
+-                this.emit('active-changed', submenuItem);
+-            }));
+-            menuItem._closingId = this.connect('open-state-changed', function(self, open) {
+-                if (!open)
+-                    menuItem.menu.close(false);
+-            });
+-        }
++    _connectSubMenuSignals: function(object, menu) {
++        object._subMenuActivateId = menu.connect('activate', Lang.bind(this, function() {
++            this.emit('activate');
++            this.close(true);
++        }));
++        object._subMenuActiveChangeId = menu.connect('active-changed', Lang.bind(this, function(submenu, submenuItem) {
++            if (this._activeMenuItem && this._activeMenuItem != submenuItem)
++                this._activeMenuItem.setActive(false);
++            this._activeMenuItem = submenuItem;
++            this.emit('active-changed', submenuItem);
++        }));
++    },
++
++    _connectItemSignals: function(menuItem) {
+         menuItem._activeChangeId = menuItem.connect('active-changed', Lang.bind(this, function (menuItem, active) {
+             if (active && this._activeMenuItem != menuItem) {
+                 if (this._activeMenuItem)
+@@ -700,6 +682,41 @@ PopupMenuBase.prototype = {
+         }));
+     },
+ 
++    addMenuItem: function(menuItem, position) {
++        let before_item = null;
++        if (position == undefined) {
++            this.box.add(menuItem.actor);
++        } else {
++            let items = this.getMenuItems();
++            if (position < items.length) {
++                before_item = items[position].actor;
++                this.box.insert_before(menuItem.actor, before_item);
++            } else
++                this.box.add(menuItem.actor);
++        }
++        if (menuItem instanceof PopupMenuSection) {
++            this._connectSubMenuSignals(menuItem, menuItem);
++            menuItem.connect('destroy', Lang.bind(this, function() {
++                menuItem.disconnect(menuItem._subMenuActivateId);
++                menuItem.disconnect(menuItem._subMenuActiveChangeId);
++            }));
++        } else if (menuItem instanceof PopupSubMenuMenuItem) {
++            if (before_item == null)
++                this.box.add(menuItem.menu.actor);
++            else
++                this.box.insert_before(menuItem.menu.actor, before_item);
++            this._connectSubMenuSignals(menuItem, menuItem.menu);
++            this._connectItemSignals(menuItem);
++            menuItem._closingId = this.connect('open-state-changed', function(self, open) {
++                if (!open)
++                    menuItem.menu.close(false);
++            });
++        } else if (menuItem instanceof PopupBaseMenuItem)
++            this._connectItemSignals(menuItem);
++        else
++            throw TypeError("Invalid argument to PopupMenuBase.addMenuItem()");
++    },
++
+     getColumnWidths: function() {
+         let columnWidths = [];
+         let items = this.box.get_children();
+@@ -728,7 +745,11 @@ PopupMenuBase.prototype = {
+     },
+ 
+     getMenuItems: function() {
+-        return this.box.get_children().map(function (actor) { return actor._delegate; }).filter(function(item) { return item instanceof PopupBaseMenuItem; });
++        return this.box.get_children().map(function (actor) {
++            return actor._delegate;
++        }).filter(function(item) {
++            return item instanceof PopupBaseMenuItem || item instanceof PopupMenuSection;
++        });
+     },
+ 
+     removeAll: function() {
+@@ -943,6 +964,34 @@ PopupSubMenu.prototype = {
+     }
+ };
+ 
++/**
++ * PopupMenuSection:
++ *
++ * A section of a PopupMenu which is handled like a submenu
++ * (you can add and remove items, you can destroy it, you
++ * can add it to another menu), but is completely transparent
++ * to the user
++ */
++function PopupMenuSection() {
++    this._init.apply(this, arguments);
++}
++
++PopupMenuSection.prototype = {
++    __proto__: PopupMenuBase.prototype,
++
++    _init: function() {
++        PopupMenuBase.prototype._init.call(this);
++
++        this.actor = this.box;
++        this.actor._delegate = this;
++        this.isOpen = true;
++    },
++
++    // deliberately ignore any attempt to open() or close()
++    open: function(animate) { },
++    close: function() { },
++}
++
+ function PopupSubMenuMenuItem() {
+     this._init.apply(this, arguments);
+ }
+-- 
+1.7.3.5
\ No newline at end of file

diff --git a/gnome-base/gnome-shell/files/gnome-shell-nm-3.patch b/gnome-base/gnome-shell/files/gnome-shell-nm-3.patch
new file mode 100644
index 0000000..64aa99c
--- /dev/null
+++ b/gnome-base/gnome-shell/files/gnome-shell-nm-3.patch
@@ -0,0 +1,1868 @@
+From 11400d81fd9775bac7db3e49e620004bb9d6fab5 Mon Sep 17 00:00:00 2001
+From: Giovanni Campagna <gcampagna@src.gnome.org>
+Date: Tue, 25 Jan 2011 22:08:12 +0100
+Subject: [PATCH] Status area: add NetworkManager indicator
+
+Adds an implementation of nm-applet in javascript. Uses the new
+introspection from NetworkManager, and temporarily requires
+nm-applet to be running for the secret service and for wireless
+dialogs.
+
+https://bugzilla.gnome.org/show_bug.cgi?id=621707
+---
+ js/Makefile.am                  |    2 +
+ js/misc/modemManager.js         |   93 +++
+ js/ui/panel.js                  |    3 +-
+ js/ui/status/network.js         | 1656 +++++++++++++++++++++++++++++++++++++++
+ tools/build/gnome-shell.modules |   19 +
+ 5 files changed, 1772 insertions(+), 1 deletions(-)
+ create mode 100644 js/misc/modemManager.js
+ create mode 100644 js/ui/status/network.js
+
+diff --git a/js/Makefile.am b/js/Makefile.am
+index e4a4145..53f80d4 100644
+--- a/js/Makefile.am
++++ b/js/Makefile.am
+@@ -8,6 +8,7 @@ nobase_dist_js_DATA = 	\
+ 	misc/format.js		\
+ 	misc/gnomeSession.js	\
+ 	misc/history.js		\
++	misc/modemManager.js	\
+ 	misc/params.js		\
+ 	misc/util.js		\
+ 	perf/core.js		\
+@@ -49,6 +50,7 @@ nobase_dist_js_DATA = 	\
+ 	ui/statusMenu.js	\
+ 	ui/status/accessibility.js	\
+ 	ui/status/keyboard.js	\
++	ui/status/network.js	\
+ 	ui/status/power.js	\
+ 	ui/status/volume.js	\
+ 	ui/status/bluetooth.js	\
+diff --git a/js/misc/modemManager.js b/js/misc/modemManager.js
+new file mode 100644
+index 0000000..104262b
+--- /dev/null
++++ b/js/misc/modemManager.js
+@@ -0,0 +1,93 @@
++// -*- mode: js2; indent-tabs-mode: nil; js2-basic-offset: 4 -*-
++const DBus = imports.dbus;
++const Lang = imports.lang;
++const Signals = imports.signals;
++
++// The following are not the complete interfaces, just the methods we need
++// (or may need in the future)
++
++const ModemGsmNetworkInterface = {
++    name: 'org.freedesktop.ModemManager.Modem.Gsm.Network',
++    methods: [
++	{ name: 'GetRegistrationInfo', inSignature: '', outSignature: 'uss' },
++	{ name: 'GetSignalQuality', inSignature: '', outSignature: 'u' },
++    ],
++    properties: [
++	{ name: 'AccessTechnology', signature: 'u', access: 'read' }
++    ],
++    signals: [
++	{ name: 'SignalQuality', inSignature: 'u' },
++	{ name: 'RegistrationInfo', inSignature: 'uss' }
++    ]
++};
++const ModemGsmNetworkProxy = DBus.makeProxyClass(ModemGsmNetworkInterface);
++
++const ModemCdmaInterface = {
++    name: 'org.freedesktop.ModemManager.Modem.Cdma',
++    methods: [
++	{ name: 'GetSignalQuality', inSignature: '', outSignature: 'u' },
++	{ name: 'GetServingSystem', inSignature: '', outSignature: 'usu' },
++    ],
++    signals: [
++	{ name: 'SignalQuality', inSignature: 'u' }
++    ]
++};
++const ModemCdmaProxy = DBus.makeProxyClass(ModemCdmaInterface);
++
++
++function ModemGsm() {
++    this._init.apply(this, arguments);
++}
++
++ModemGsm.prototype = {
++    _init: function(path) {
++	this._proxy = new ModemGsmNetworkProxy(DBus.system, 'org.freedesktop.ModemManager', path);
++
++	this.signal_quality = 0;
++	this.operator_name = null;
++	this._proxy.connect('SignalQuality', Lang.bind(this, this._qualityChanged));
++	this._proxy.connect('RegistrationInfo', Lang.bind(this, this._registrationInfoChanged));
++	this._proxy.GetRegistrationInfoRemote(Lang.bind(this, this._registrationInfoChanged));
++	this._proxy.GetSignalQualityRemote(Lang.bind(this, this._qualityChanged));
++    },
++
++    _registrationInfoChanged: function(status, code, name) {
++	if (name.length > 0)
++	    this.operator_name = name;
++	else
++	    this.operator_name = null;
++	this.emit('notify::operator-name');
++    },
++
++    _qualityChanged: function(quality) {
++        this.signal_quality = quality;
++        this.emit('notify::signal-quality');
++    }
++}
++
++function ModemCdma() {
++    this._init.apply(this, arguments);
++}
++
++ModemCdma.prototype = {
++    _init: function(path) {
++        this._proxy = new ModemCdmaProxy(DBus.system, 'org.freedesktop.ModemManager', path);
++
++        this.signal_quality = 0;
++        this.operator_name = null;
++        this._proxy.connect('SignalQuality', Lang.bind(this, this._qualityChanged));
++        this._proxy.GetSignalQualityRemote(Lang.bind(this, this._qualityChanged));
++        this._proxy.GetServingSystemRemote(Lang.bind(this, function(status, name, code) {
++            if (name.length > 0)
++                this.operator_name = name;
++            else
++                this.operator_name = null;
++            this.emit('notify::operator-name');
++        }));
++    },
++
++    _qualityChanged: function(quality) {
++        this.signal_quality = quality;
++        this.emit('notify::signal-quality');
++    }
++};
+\ No newline at end of file
+diff --git a/js/ui/panel.js b/js/ui/panel.js
+index f1a5e90..46355c4 100644
+--- a/js/ui/panel.js
++++ b/js/ui/panel.js
+@@ -37,7 +37,8 @@ const STANDARD_TRAY_ICON_SHELL_IMPLEMENTATION = {
+     'a11y': imports.ui.status.accessibility.ATIndicator,
+     'volume': imports.ui.status.volume.Indicator,
+     'battery': imports.ui.status.power.Indicator,
+-    'keyboard': imports.ui.status.keyboard.XKBIndicator
++    'keyboard': imports.ui.status.keyboard.XKBIndicator,
++    'network': imports.ui.status.network.NMApplet
+ };
+ 
+ if (Config.HAVE_BLUETOOTH)
+diff --git a/js/ui/status/network.js b/js/ui/status/network.js
+new file mode 100644
+index 0000000..a0cd576
+--- /dev/null
++++ b/js/ui/status/network.js
+@@ -0,0 +1,1656 @@
++// -*- mode: js2; indent-tabs-mode: nil; js2-basic-offset: 4 -*-
++const ByteArray = imports.byteArray;
++const DBus = imports.dbus;
++const GLib = imports.gi.GLib;
++const Lang = imports.lang;
++const Mainloop = imports.mainloop;
++const NetworkManager = imports.gi.NetworkManager;
++const NMClient = imports.gi.NMClient;
++const Shell = imports.gi.Shell;
++const Signals = imports.signals;
++const St = imports.gi.St;
++
++const Main = imports.ui.main;
++const PanelMenu = imports.ui.panelMenu;
++const PopupMenu = imports.ui.popupMenu;
++const MessageTray = imports.ui.messageTray;
++const ModemManager = imports.misc.modemManager;
++const Util = imports.misc.util;
++
++const Gettext = imports.gettext.domain('gnome-shell');
++const _ = Gettext.gettext;
++
++const NMAppletIface = {
++    name: 'org.freedesktop.NetworkManager.Applet',
++    methods: [
++        { name: 'ConnectToHiddenNetwork', outSignature: '', inSignature: '' },
++        { name: 'CreateWirelessNetwork', outSignature: '', inSignature: '' },
++    ]
++};
++const NMAppletProxy = DBus.makeProxyClass(NMAppletIface);
++
++function macToArray(string) {
++    const regexp = /([A-Fa-f0-9]{2}):([A-Fa-f0-9]{2}):([A-Fa-f0-9]{2}):([A-Fa-f0-9]{2}):([A-Fa-f0-9]{2}):([A-Fa-f0-9]{2})/;
++    let match = regexp.exec(string);
++    if (match) {
++        // remove the global match
++        match.splice(0, 1);
++        return match.map(function(el) {
++            return parseInt(el, 16);
++        });
++    } else
++        return new Array(6);
++}
++
++function macCompare(one, two) {
++    for (let i = 0; i < 6; i++) {
++        if (one[i] != two[i])
++            return false;
++    }
++    return true;
++}
++
++/**
++ * makeClassKey:
++ * @object: any Object
++ *
++ * Returns a string which can be used to identify @object's [[Class]]
++ */
++function makeClassKey(object) {
++    return Object.prototype.toString.call(object);
++}
++
++function addChipersFromFlags(settings, flags) {
++    // helper copied from nm-applet
++
++    if (flags & NetworkManager['802_11_AP_SEC_PAIR_TKIP'])
++	settings.add_pairwise('tkip');
++    if (flags & NetworkManager['802_11_AP_SEC_PAIR_CCMP'])
++        settings.add_pairwise('ccmp');
++
++    if (flags & NetworkManager['802_11_AP_SEC_GROUP_WEP40'])
++        settings.add_group('wep40');
++    if (flags & NetworkManager['802_11_AP_SEC_GROUP_WEP104'])
++        settings.add_group('wep104');
++    if (flags & NetworkManager['802_11_AP_SEC_GROUP_TKIP'])
++        settings.add_group('tkip');
++    if (flags & NetworkManager['802_11_AP_SEC_GROUP_CCMP'])
++        settings.add_group('ccmp');
++}
++
++// shared between NMAccessPointMenuItem and NMDeviceWWAN
++function signalToIcon(value) {
++    if(value > 80)
++        return 'excellent';
++    if(value > 55)
++        return 'good';
++    if(value > 30)
++        return 'ok';
++    if(value > 5)
++        return 'weak';
++    return 'none';
++}
++
++function NMAccessPointMenuItem() {
++    this._init.apply(this, arguments);
++}
++
++NMAccessPointMenuItem.prototype = {
++    __proto__: PopupMenu.PopupImageMenuItem.prototype,
++
++    _init: function(accessPoint, title, params) {
++        this._accessPoint = accessPoint;
++        this._title = title || String(accessPoint.get_ssid());
++
++        PopupMenu.PopupImageMenuItem.prototype._init.call(this, this._title, this._get_icon(), params);
++
++        this._updateId = this._accessPoint.connect('notify::strength', Lang.bind(this, this._updated));
++    },
++
++    _updated: function() {
++        this.setIcon(this._get_icon());
++    },
++
++    _get_icon: function() {
++        return 'network-wireless-signal-' + signalToIcon(this._accessPoint.strength);
++    },
++
++    destroy: function() {
++        if (this._updateId) {
++            this._accessPoint.disconnect(this._updateId);
++            this._updateId = 0;
++        }
++
++        PopupMenu.PopupImageMenuItem.prototype.destroy.call(this);
++    }
++};
++
++function NMDevice() {
++    throw TypeError('Instantanting abstract class NMDevice');
++}
++
++NMDevice.prototype = {
++    _init: function(client, device, connections, activeConnectionPosition) {
++        /* <protected> */
++        this.client = client;
++        this.device = device;
++        if (device) {
++            this.device._delegate = this;
++            this.device.connect('state-changed', Lang.bind(this, this.deviceStateChanged));
++        }
++
++        this.connections = [ ];
++        for (let i = 0; i < connections.length; i++) {
++            if (!connections[i]._uuid)
++                continue;
++            if (!this.connectionValid(connections[i]))
++                continue;
++            // record the connection
++            let obj = {
++                connection: connections[i],
++                name: connections[i]._name,
++                uuid: connections[i]._uuid,
++            };
++            this.connections.push(obj);
++        }
++        this.activeConnection = null;
++        this.activeConnectionItem = null;
++        this.disconnectItem = null;
++        this.autoConnectionItem = null;
++        this.statusItem = null;
++
++        /* <private> */
++        this._activeConnectionPosition = activeConnectionPosition || 0;
++
++        /* <public> */
++        this.titleItem = new PopupMenu.PopupMenuItem(this.device._description, { reactive: false, style_class: 'popup-subtitle-menu-item' });
++        this.section = new PopupMenu.PopupMenuSection();
++
++        this.createSection();
++    },
++
++    setActiveConnection: function(activeConnection) {
++        if (this.activeConnection && activeConnection == this.activeConnection)
++            // nothing to do
++            return;
++
++        // remove any UI
++        if (this.activeConnectionItem) {
++            this.activeConnectionItem.destroy();
++            this.activeConnectionItem = null;
++        }
++
++        if (this.disconnectItem)  {
++            this.disconnectItem.destroy();
++            this.disconnectItem = null;
++        }
++
++        let previousActive = this.activeConnection;
++        this.activeConnection == null;
++
++        if (previousActive && previousActive._connection) {
++            // add the connection back as a normal one, by removing and adding it
++            this.removeConnection(previousActive._connection, true);
++            this.addConnection(previousActive._connection);
++        }
++
++        if (activeConnection) {
++            if (activeConnection._connection) {
++                // remove the connection if it was already seen
++                let pos = this.findConnection(activeConnection._connection._uuid);
++                if (pos != -1) {
++                    let obj = this.connections[pos];
++                    if (obj.item)
++                        obj.item.destroy();
++                    obj.item = null;
++                }
++            }
++
++            this.activeConnection = activeConnection;
++            this.createActiveConnectionItems();
++            if (this.disconnectItem)
++                this.section.addMenuItem(this.disconnectItem, this._activeConnectionPosition);
++            this.section.addMenuItem(this.activeConnectionItem, this._activeConnectionPosition);
++        }
++    },
++
++    addConnection: function(connection) {
++        if (this.findConnection(connection._uuid) != -1) {
++            log('Connection already added to menu, not adding again');
++            return;
++        }
++
++        // record the connection
++        let obj = {
++            connection: connection,
++            name: connection._name,
++            uuid: connection._uuid,
++        };
++        this.connections.push(obj);
++
++        if (!this.device ||
++            (this.device.state == NetworkManager.DeviceState.DISCONNECTED ||
++             this.device.state == NetworkManager.DeviceState.ACTIVATED)) {
++            // we need to show this connection
++            if (!this.hasAuto) {
++                // already showing the connection list
++                obj.item = this.createConnectionItem(obj);
++                this.section.addMenuItem(obj.item);
++            } else {
++                // First connection in the list
++                this.clearSection();
++                this.createSection();
++            }
++        }
++    },
++
++    removeConnection: function(connection, skipCreateAuto) {
++        if (!connection._uuid)
++            return;
++        let pos = this.findConnection(connection._uuid);
++        if (pos == -1)
++            return;
++
++        let obj = this.connections[pos];
++        if (obj.item)
++            obj.item.destroy();
++        this.connections.splice(pos, 1);
++
++        if (this.connections.length == 0 && !skipCreateAuto) {
++            // We need to show the automatic connection again
++            this.clearSection();
++            this.createSection();
++        }
++    },
++
++    connectionValid: function(connection) {
++        throw TypeError('Invoking pure virtual function NMDevice.connectionValid');
++    },
++
++    /* <protected> */
++    createAutomaticConnection: function() {
++        throw TypeError('Invoking pure virtual function NMDevice.createAutomaticConnection');
++    },
++
++    findConnection: function(uuid) {
++        for (let i = 0; i < this.connections.length; i++) {
++            let obj = this.connections[i];
++            if (obj.uuid == uuid)
++                return i;
++        }
++        return -1;
++    },
++
++    clearSection: function() {
++        // Clear everything
++        this.section.removeAll();
++        this.autoConnectionItem = null;
++        this.activeConnectionItem = null;
++        this.disconnectItem = null;
++        this.statusItem = null;
++        for (let i = 0; i < this.connections.length; i++) {
++            this.connections[i].item = null;
++        }
++    },
++
++    createSection: function() {
++        let status;
++        if (!this.device ||
++            (this.device.state == NetworkManager.DeviceState.DISCONNECTED ||
++             this.device.state == NetworkManager.DeviceState.ACTIVATED))
++            this.createConnectionList();
++        else if (this.device.state != NetworkManager.DeviceState.UNMANAGED) {
++            let title = this.getStatusLabel();
++            this.statusItem = new PopupMenu.PopupMenuItem(title, { reactive: false, style_class: 'popup-inactive-menu-item' });
++            this.section.addMenuItem(this.statusItem);
++        }
++        // else do nothing, the menu should remain empty
++    },
++
++    getStatusLabel: function() {
++        switch(this.device.state) {
++        case NetworkManager.DeviceState.DISCONNECTED:
++        case NetworkManager.DeviceState.ACTIVATED:
++            log('Attempt to show status for a disconnected / activate device, should be showing connection list instead');
++            return 'invalid';
++        case NetworkManager.DeviceState.PREPARE:
++        case NetworkManager.DeviceState.CONFIG:
++        case NetworkManager.DeviceState.IP_CONFIG:
++            return _("connecting...");
++        case NetworkManager.DeviceState.NEED_AUTH:
++            return _("authentication required");
++        case NetworkManager.DeviceState.UNAVAILABLE:
++            if ((this.device.capabilities & NetworkManager.DeviceCapabilities.CARRIER_DETECT) &&
++                !this.device.carrier)
++                return _("network cable unplugged");
++            else
++                return _("network unavailable");
++        case NetworkManager.DeviceState.FAILED:
++            return _("connection failed");
++        default:
++            log('Device state invalid, is %d'.format(this.device.state));
++            return 'invalid';
++        }
++    },
++
++    createConnectionList: function() {
++        if (this.activeConnection) {
++            this.createActiveConnectionItems();
++            this.section.addMenuItem(this.activeConnectionItem);
++            if (this.disconnectItem)
++                this.section.addMenuItem(this.disconnectItem);
++        }
++        if (this.connections.length > 0) {
++            for(let j = 0; j < this.connections.length; ++j) {
++                let obj = this.connections[j];
++                if (this.activeConnection && obj.connection == this.activeConnection._connection)
++                    continue;
++                obj.item = this.createConnectionItem(obj);
++                this.section.addMenuItem(obj.item);
++            }
++        } else if (this.autoConnectionName) {
++            this.autoConnectionItem = new PopupMenu.PopupMenuItem(this.autoConnectionName);
++            this.autoConnectionItem.connect('activate', Lang.bind(this, function() {
++                let connection = this.createAutomaticConnection();
++                this.client.add_and_activate_connection(connection, this.device, null, function() { });
++            }));
++            this.section.addMenuItem(this.autoConnectionItem);
++        }
++    },
++
++    createConnectionItem: function(obj) {
++        let path = obj.connection.path;
++        let item = new PopupMenu.PopupMenuItem(obj.name);
++        item.connect('activate', Lang.bind(this, function() {
++            this.client.activate_connection(path, this.device, null, function() { });
++        }));
++        return item;
++    },
++
++    createActiveConnectionItems: function() {
++        let title;
++        let active = this.activeConnection._connection;
++        this.disconnectItem = null;
++        if (active) {
++            title = active._name;
++            this.disconnectItem = new PopupMenu.PopupMenuItem(_("Disconnect"));
++            this.disconnectItem.connect('activate', Lang.bind(this, function() {
++                /* The correct approach would be
++                   this.client.deactivate_connection(this.activeConnection);
++                   but with this, NM insists in restarting the connection immediately
++                */
++                this.device.disconnect(function() { });
++            }));
++        } else {
++            /* TRANSLATORS: this is the indication that a connection for another logged in user is active,
++               and we cannot access its settings (including the name) */
++            title = _("Connected (private)");
++        }
++        this.activeConnectionItem = new PopupMenu.PopupMenuItem(title, { reactive: false });
++        this.activeConnectionItem.setShowDot(true);
++    },
++
++    deviceStateChanged: function(device, newstate, oldstate, reason) {
++        if (newstate == oldstate) {
++            log('device emitted state-changed without actually changing state');
++            return;
++        }
++
++        if (oldstate == NetworkManager.DeviceState.ACTIVATED) {
++            this.emit('network-lost');
++        }
++
++        switch(newstate) {
++        case NetworkManager.DeviceState.UNMANAGED:
++            // clear everything and be quiet
++            this.clearSection();
++            return;
++        case NetworkManager.DeviceState.NEED_AUTH:
++            // FIXME: make this have a real effect
++            this.emit('need-auth');
++            break;
++        case NetworkManager.DeviceState.FAILED:
++            this.emit('activation-failed', reason);
++            break;
++        }
++
++        if (newstate != NetworkManager.DeviceState.DISCONNECTED &&
++            newstate != NetworkManager.DeviceState.ACTIVATED &&
++            oldstate != NetworkManager.DeviceState.DISCONNECTED &&
++            oldstate != NetworkManager.DeviceState.ACTIVATED &&
++            oldstate != NetworkManager.DeviceState.UNMANAGED) {
++            // a transition between states that show the status label
++            this.statusItem.label.text = this.getStatusLabel();
++            return;
++        }
++
++        // just refresh everything
++        this.clearSection();
++        this.createSection();
++    }
++};
++Signals.addSignalMethods(NMDevice.prototype);
++
++
++function NMDeviceWired() {
++    this._init.apply(this, arguments);
++}
++
++NMDeviceWired.prototype = {
++    __proto__: NMDevice.prototype,
++
++    _init: function(client, device, connections) {
++        this.autoConnectionName = _("Auto Ethernet");
++        this.category = 'wired';
++
++        NMDevice.prototype._init.call(this, client, device, connections);
++    },
++
++    connectionValid: function(connection) {
++        if (connection._type != '802-3-ethernet')
++            return false;
++
++        let ethernetSettings = connection.get_setting_by_name('802-3-ethernet');
++        let fixedMac = ethernetSettings.get_mac_address();
++        if (fixedMac)
++            return macCompare(fixedMac, macToArray(this.device.perm_hw_address));
++        return true;
++    },
++
++    createAutomaticConnection: function() {
++        let connection = new NetworkManager.Connection();
++        connection._uuid = NetworkManager.utils_uuid_generate();
++        connection.add_setting(new NetworkManager.SettingWired());
++        connection.add_setting(new NetworkManager.SettingConnection({
++            uuid: connection._uuid,
++            id: this.autoConnectionName,
++            type: '802-3-ethernet',
++            autoconnect: true
++        }));
++        return connection;
++    }
++};
++
++function NMDeviceWWAN() {
++    this._init.apply(this, arguments);
++}
++
++NMDeviceWWAN.prototype = {
++    __proto__: NMDevice.prototype,
++
++    _init: function(client, device, connections) {
++        this.autoConnectionName = _("New Mobile Broadband connection...");
++        this.category = 'wwan';
++
++        if (device instanceof NMClient.GsmDevice) {
++            this.mobileDevice = new ModemManager.ModemGsm(device.udi);
++            this._connectionType = 'gsm';
++        } else if (device instanceof NMClient.CdmaDevice) {
++            this.mobileDevice = new ModemManager.ModemCdma(device.udi);
++            this._connectionType = 'cdma';
++        }
++
++        this.mobileDevice.connect('notify::operator-name', Lang.bind(this, function() {
++            if (this._operatorItem) {
++                let name = this.mobileDevice.operator_name;
++                if (name) {
++                    this._operatorItem.label.text = name;
++                    this._operatorItem.actor.show();
++                } else
++                    this._operatorItem.actor.hide();
++            }
++        }));
++        this.mobileDevice.connect('notify::signal-quality', Lang.bind(this, function() {
++            if (this._operatorItem) {
++                this._operatorItem.setIcon(this._get_signal_icon());
++            }
++        }));
++
++        NMDevice.prototype._init.call(this, client, device, connections, 1);
++    },
++
++    _get_signal_icon: function() {
++        return 'network-cellular-signal-' + signalToIcon(this.mobileDevice.signal_quality);
++    },
++
++    createSection: function() {
++        NMDevice.prototype.createSection.call(this);
++
++        this._operatorItem = new PopupMenu.PopupImageMenuItem(this.mobileDevice.operator_name || '', this._get_signal_icon(), { reactive: false });
++        this.section.addMenuItem(this._operatorItem, 0);
++    },
++
++    clearSection: function() {
++        this._operatorItem = null;
++
++        NMDevice.prototype.clearSection.call(this);
++    },
++
++    connectionValid: function(connection) {
++        return connection._type == this._connectionType;
++    },
++
++    createAutomaticConnection: function() {
++        // FIXME: we need to summon the mobile wizard here
++        // or NM will not have the necessary parameters to complete the connection
++
++        let connection = new NetworkManager.Connection;
++        connection._uuid = NetworkManager.utils_uuid_generate();
++        connection.add_setting(new NetworkManager.SettingConnection({
++            uuid: connection._uuid,
++            id: this.autoConnectionName,
++            type: this._connectionType,
++            autoconnect: false
++        }));
++        return connection;
++    }
++};
++
++function NMDeviceBluetooth() {
++    this._init.apply(this, arguments);
++}
++
++NMDeviceBluetooth.prototype = {
++    __proto__: NMDevice.prototype,
++
++    _init: function(client, device, connections) {
++        this.autoConnectionName = _("New Mobile Broadband connection...");
++        this.category = 'wwan';
++
++        NMDevice.prototype._init.call(this, client, device, connections);
++    },
++
++    connectionValid: function(connection) {
++        if (connection._type != 'bluetooth')
++            return false;
++
++        let bluetoothSettings = connection.get_setting_by_name('bluetooth');
++        let fixedBdaddr = bluetoothSettings.get_bdaddr();
++        if (fixedBdaddr)
++            return macCompare(fixedBdaddr, macToArray(this.device.hw_address));
++
++        return true;
++    },
++
++    createAutomaticConnection: function() {
++        // XXX: is this enough? or do we need other stuff from bluetoothd?
++
++        let connection = new NetworkManager.Connection;
++        connection._uuid = NetworkManager.utils_uuid_generate();
++        connection.add_setting(new NetworkManager.SettingConnection({
++            uuid: connection._uuid,
++            id: this.autoConnectionName,
++            type: 'gsm',
++            autoconnect: false
++        }));
++        return connection;
++    }
++};
++
++
++// Not a real device, but I save a lot code this way
++function NMDeviceVPN() {
++    this._init.apply(this, arguments);
++}
++
++NMDeviceVPN.prototype = {
++    __proto__: NMDevice.prototype,
++
++    _init: function(client) {
++        // Disable autoconnections
++        this.autoConnectionName = null;
++        this.category = 'vpn';
++
++        NMDevice.prototype._init.call(this, client, null, [ ]);
++    },
++
++    connectionValid: function(connection) {
++        return connection._type == 'vpn';
++    }
++};
++
++function NMDeviceWireless() {
++    this._init.apply(this, arguments);
++}
++
++NMDeviceWireless.prototype = {
++    __proto__: NMDevice.prototype,
++
++    _init: function(client, device, connections) {
++        this.category = 'wireless';
++
++        this._overflowItem = null;
++        this._accessPoints = [ ];
++
++        // XXX: breaking the layers with this, but cannot call
++        // this.connectionValid until I have a device
++        this.device = device;
++
++        let validConnections = connections.filter(Lang.bind(this, function(connection) {
++            return this.connectionValid(connection);
++        }));
++        let accessPoints = device.get_access_points() || [ ];
++        for (let i = 0; i < accessPoints.length; i++) {
++            // Access points are grouped by network name
++            let ap = accessPoints[i];
++            let name = String(ap.get_ssid());
++            let pos = this._findAccessPoint(name);
++            let obj;
++            if (pos != -1) {
++                obj = this._accessPoints[pos];
++                obj.accessPoints.push(ap);
++                obj.accessPoints.sort(function(one, two) {
++                    return two.strength - one.strength;
++                });
++            } else {
++                obj = { name: name,
++                        connections: [ ],
++                        item: null,
++                        accessPoints: [ ap ]
++                      };
++                this._accessPoints.push(obj);
++            }
++
++            // Check if some connection is valid for this AP
++            for (let j = 0; j < validConnections.length; j++) {
++                let connection = validConnections[j];
++                if (this._connectionValidForAP(connection, ap) &&
++                    obj.connections.indexOf(connection) == -1) {
++                    obj.connections.push(connection);
++                }
++            }
++        }
++        device.connect('access-point-added', Lang.bind(this, this._accessPointAdded));
++        device.connect('access-point-removed', Lang.bind(this, this._accessPointRemoved));
++
++        NMDevice.prototype._init.call(this, client, device, validConnections);
++    },
++
++    _findAccessPoint: function(name) {
++        for (let i = 0; i < this._accessPoints.length; i++) {
++            if (this._accessPoints[i].name == name)
++                return i;
++        }
++        return -1;
++    },
++
++    _accessPointAdded: function(device, accessPoint) {
++        let name = String(accessPoint.get_ssid());
++        let pos = this._findAccessPoint(name);
++        let apObj;
++        if (pos != -1) {
++            apObj = this._accessPoints[pos];
++            if (apObj.accessPoints.indexOf(accessPoint) != -1) {
++                // already seen this AP
++                return;
++            }
++
++            apObj.accessPoints.push(accessPoint);
++            apObj.accessPoints.sort(function(one, two) {
++                return two.strength - one.strength;
++            });
++
++        } else {
++            apObj = { name: name,
++                      connections: [ ],
++                      item: null,
++                      accessPoints: [ accessPoint ]
++                    };
++            this._accessPoints.push(apObj);
++        }
++
++        // check if this enables new connections for this group
++        for (let i = 0; i < this.connections.length; i++) {
++            let connection = this.connections[i].connection;
++            if (this._connectionValidForAP(connection, accessPoint) &&
++                apObj.connections.indexOf(connection) == -1) {
++                apObj.connections.push(connection);
++            }
++        }
++
++        if (this.device.state == NetworkManager.DeviceState.DISCONNECTED ||
++            this.device.state == NetworkManager.DeviceState.ACTIVATED) {
++            // update everything (it would be too complicated to update just what has changed)
++            this.clearSection();
++            this.createConnectionList();
++        }
++    },
++
++    _accessPointRemoved: function(device, accessPoint) {
++        let name = String(accessPoint.get_ssid());
++        let pos = this._findAccessPoint(name);
++
++        if (pos == -1) {
++            log('Removing an access point that was never added');
++            return;
++        }
++
++        let apObj = this._accessPoints[pos];
++        let i = apObj.accessPoints.indexOf(accessPoint);
++
++        if (i == -1) {
++            log('Removing an access point that was never added');
++            return;
++        }
++
++        apObj.accessPoints.splice(i, 1);
++
++        if (apObj.accessPoints.length == 0) {
++            if (apObj.item)
++                apObj.item.destroy();
++            this._accessPoints.splice(pos, 1);
++        }
++    },
++
++    _createAPItem: function(connection, accessPointObj, useConnectionName) {
++        accessPointObj.accessPoints.sort(function(one, two) {
++            return two.strength - one.strength;
++        });
++        let item = new NMAccessPointMenuItem(accessPointObj.accessPoints[0], useConnectionName ? connection._name : undefined);
++        item._connection = connection;
++        item.connect('activate', Lang.bind(this, function() {
++            // always connect to the strongest access point in a group
++            let apList = accessPointObj.accessPoints;
++            apList.sort(function(one, two) {
++                return two.strength - one.strength;
++            });
++            for (let i = 0; i < apList.length; i++) {
++                if (this._connectionValidForAP(connection, apList[i])) {
++                    this.client.activate_connection(connection.path, this.device, apList[i].dbus_path, function() { });
++                    break;
++                }
++            }
++        }));
++        return item;
++    },
++
++    connectionValid: function(connection) {
++        if (connection._type != '802-11-wireless')
++            return false;
++
++        let wirelessSettings = connection.get_setting_by_name('802-11-wireless');
++        let wirelessSecuritySettings = connection.get_setting_by_name('802-11-wireless-security');
++
++        let fixedMac = wirelessSettings.get_mac_address();
++        if (fixedMac && !macCompare(fixedMac, macToArray(this.device.perm_hw_address)))
++            return false;
++
++        if (wirelessSecuritySettings &&
++            wirelessSecuritySettings.key_mgmt != 'none' &&
++            wirelessSecuritySettings.key_mgmt != 'ieee8021x') {
++            let capabilities = this.device.wireless_capabilities;
++            if (!(capabilities & NetworkManager.DeviceWifiCapabilities.WPA) ||
++                !(capabilities & NetworkManager.DeviceWifiCapabilities.CIPHER_TKIP))
++                return false;
++            if (wirelessSecuritySettings.get_num_protos() == 1 &&
++                wirelessSecuritySettings.get_proto(0) == 'rsn' &&
++                !(capabilities & NetworkManager.DeviceWifiCapabilities.RSN))
++                return false;
++            if (wirelessSecuritySettings.get_num_pairwise() == 1 &&
++                wirelessSecuritySettings.get_pairwise(0) == 'ccmp' &&
++                !(capabilities & NetworkManager.DeviceWifiCapabilities.CIPHER_CCMP))
++                return false;
++            if (wirelessSecuritySettings.get_num_groups() == 1 &&
++                wirelessSecuritySettings.get_group(0) == 'ccmp' &&
++                !(capabilities & NetworkManager.DeviceWifiCapabilities.CIPHER_CCMP))
++                return false;
++        }
++        return true;
++    },
++
++    clearSection: function() {
++        NMDevice.prototype.clearSection.call(this);
++
++        for (let i = 0; i < this._accessPoints.length; i++)
++            this._accessPoints[i].item = null;
++        this._overflowItem = null;
++    },
++
++    removeConnection: function(connection, skipCreateAuto) {
++        if (!connection._uuid)
++            return;
++        let pos = this.findConnection(connection._uuid);
++        if (pos == -1)
++            return;
++
++        let obj = this.connections[pos];
++        this.connections.splice(pos, 1);
++
++        let anyauto = false, forceupdate = false;
++        for (let i = 0; i < this._accessPoints.length; i++) {
++            let apObj = this._accessPoints[i];
++            let connections = apObj.connections;
++            for (let k = 0; k < connections.length; k++) {
++                if (connections[k]._uuid == connection._uuid) {
++                    // remove the connection from the access point group
++                    connections.splice(k);
++                    anyauto = true;
++                    if (apObj.item) {
++                        if (apObj.item instanceof PopupMenu.PopupSubMenuMenuItem) {
++                            let items = apObj.item.menu.getMenuItems();
++                            if (items.length == 2) {
++                                // we need to update the connection list to convert this to a normal item
++                                forceupdate = true;
++                            } else {
++                                for (let j = 0; j < items.length; j++) {
++                                    if (items[j]._connection._uuid == connection._uuid) {
++                                        items[j].destroy();
++                                        break;
++                                    }
++                                }
++                            }
++                        } else {
++                            apObj.item.destroy();
++                            apObj.item = null;
++                        }
++                    }
++                }
++            }
++        }
++
++        if (forceupdate || (anyauto && !skipCreateAuto)) {
++            this.clearSection();
++            this.createConnectionList();
++        }
++    },
++
++    addConnection: function(connection) {
++        if (this.findConnection(connection._uuid) != -1) {
++            log('Connection already added to menu, not adding again');
++            return;
++        }
++
++        // record the connection
++        let obj = {
++            connection: connection,
++            name: connection._name,
++            uuid: connection._uuid,
++        };
++        this.connections.push(obj);
++
++        // find an appropriate access point
++        let any = false;
++        for (let i = 0; i < this._accessPoints.length; i++) {
++            let apObj = this._accessPoints[i];
++
++            // Check if connection is valid for any of these access points
++            let any = false;
++            for (let k = 0; k < apObj.accessPoints.length; k++) {
++                let ap = apObj.accessPoints[k];
++                if (this._connectionValidForAP(connection, ap)) {
++                    apObj.connections.push(connection);
++                    any = true;
++                    break;
++                }
++            }
++
++            if (any &&
++                (this.device.state == NetworkManager.DeviceState.DISCONNECTED ||
++                 this.device.state == NetworkManager.DeviceState.ACTIVATED)) {
++                // we need to show this connection
++                if (apObj.item && apObj.connections.length > 2) {
++                    // We're already showing the submenu for this access point
++                    apObj.item.menu.addMenuItem(this._createAPItem(connection, apObj, true));
++                } else {
++                    if (apObj.item)
++                        apObj.item.destroy();
++                    if (apObj.connections.length == 1) {
++                        apObj.item = this._createAPItem(connection, apObj, false);
++                    } else {
++                        apObj.item = new PopupMenu.PopupSubMenuMenuItem(apObj.name);
++                        apObj.item.menu.addMenuItem(this._createAPItem(connection, apObj, true));
++                    }
++                    this.section.addMenuItem(apObj.item);
++                }
++            }
++        }
++    },
++
++    _connectionValidForAP: function(connection, ap) {
++        // copied and adapted from nm-applet
++        let wirelessSettings = connection.get_setting_by_name('802-11-wireless');
++        if (wirelessSettings.get_ssid() != String(ap.get_ssid()))
++            return false;
++
++        let wirelessSecuritySettings = connection.get_setting_by_name('802-11-wireless-security');
++
++        let fixedBssid = wirelessSettings.get_bssid();
++        if (fixedBssid && !macCompare(fixedBssid, macToArray(ap.hw_address)))
++            return false;
++
++        let fixedBand = wirelessSettings.band;
++        if (fixedBand) {
++            let freq = ap.frequency;
++            if (fixedBand == 'a' && (freq < 4915 || freq > 5825))
++                return false;
++            if (fixedBand == 'bg' && (freq < 2412 || freq > 2484))
++                return false;
++        }
++
++        let fixedChannel = wirelessSettings.channel;
++        if (fixedChannel && fixedChannel != NetworkManager.utils_wifi_freq_to_channel(ap.frequency))
++            return false;
++
++        if (!wirelessSettings.ap_security_compatible(wirelessSecuritySettings, ap.flags, ap.wpa_flags, ap.rsn_flags, ap.mode))
++            return false;
++        return true;
++    },
++
++    createActiveConnectionItems: function() {
++        let activeAp = this.device.active_access_point;
++        let icon, title;
++        if (this.activeConnection._connection) {
++            let connection = this.activeConnection._connection;
++            if (activeAp)
++                this.activeConnectionItem = new NMAccessPointMenuItem(activeAp, undefined, { reactive: false });
++            else
++                this.activeConnectionItem = new PopupMenu.PopupImageMenuItem(connection._name, 'network-wireless-connected', { reactive: false });
++            this.disconnectItem = new PopupMenu.PopupMenuItem(_("Disconnect"));
++            this.disconnectItem.connect('activate', Lang.bind(this, function() {
++                this.device.disconnect(function() { });
++            }));
++        } else {
++            // We cannot read the connection (due to ACL, most likely), but we still show signal if we have it
++            let menuItem;
++            if (activeAp)
++                this.activeConnectionItem = new NMAccessPointMenuItem(activeAp, undefined, { reactive: false });
++            else
++                this.activeConnectionItem = new PopupMenu.PopupImageMenuItem(_("Connected (private)"), 'network-wireless-connected', { reactive: false });
++        }
++        this.activeConnectionItem.setShowDot(true);
++    },
++
++    createConnectionList: function() {
++        if(this.activeConnection) {
++            this.createActiveConnectionItems();
++            this.section.addMenuItem(this.activeConnectionItem);
++            if (this.disconnectItem)
++                this.section.addMenuItem(this.disconnectItem);
++        }
++
++        let activeAp = this.device.active_access_point;
++        let activeApName = activeAp ? String(activeAp.get_ssid()) : null;
++
++        for(let j = 0; j < this._accessPoints.length; j++) {
++            let apObj = this._accessPoints[j];
++            if(apObj.name == activeApName)
++                continue;
++
++            let menuItem;
++            if(apObj.connections.length > 0) {
++                if (apObj.connections.length == 1)
++                    apObj.item = this._createAPItem(apObj.connections[0], apObj, false);
++                else {
++                    apObj.item = new PopupMenu.PopupSubMenuMenuItem(apObj.name);
++                    apObj.item._apObj = apObj;
++                    for (let i = 0; i < apObj.connections.length; i++)
++                        menuItem.menu.addMenuItem(this._createAPItem(apObj.connections[i], apObj, true));
++                }
++            } else {
++                apObj.item = new NMAccessPointMenuItem(apObj.accessPoints[0]);
++                apObj.item._apObj = apObj;
++                apObj.item.connect('activate', Lang.bind(this, function() {
++                    let connection = new NetworkManager.Connection();
++                    connection.add_setting(new NetworkManager.SettingWireless());
++                    connection.add_setting(new NetworkManager.SettingConnection({
++                        /* TRANSLATORS: this the automatic wireless connection name (including the network name) */
++                        id: _("Auto %s").format(apObj.name),
++                        autoconnect: true, // NetworkManager will know to ignore this if appropriate
++                        uuid: NetworkManager.utils_uuid_generate(),
++                        type: '802-11-wireless'
++                    }));
++
++                    this.client.add_and_activate_connection(connection, this.device, apObj.accessPoints[0].dbus_path, function() { })
++                }));
++            }
++
++            if (j <= 5)
++                this.section.addMenuItem(apObj.item);
++            else {
++                if (!this._overflowItem) {
++                    this._overflowItem = new PopupMenu.PopupSubMenuMenuItem(_("More..."));
++                }
++                this._overflowItem.menu.addMenuItem(menuItem);
++            }
++        }
++    },
++};
++
++function NMApplet() {
++    this._init.apply(this, arguments);
++}
++NMApplet.prototype = {
++    __proto__: PanelMenu.SystemStatusButton.prototype,
++
++    _init: function() {
++        PanelMenu.SystemStatusButton.prototype._init.call(this, 'network-error');
++
++        this._client = NMClient.Client.new();
++        this._nmApplet = new NMAppletProxy(DBus.session, 'org.freedesktop.NetworkManager.Applet', '/org/freedesktop/NetworkManager/Applet');
++
++        this._statusSection = new PopupMenu.PopupMenuSection();
++        this._statusItem = new PopupMenu.PopupMenuItem('', { style_class: 'popup-inactive-menu-item', reactive: false });
++        this._statusSection.addMenuItem(this._statusItem);
++        this._statusSection.addAction(_("Enable networking"), Lang.bind(this, function() {
++            this._client.networking_enabled = true;
++        }));
++        this._statusSection.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
++        this.menu.addMenuItem(this._statusSection);
++
++        this._allSections = [ ];
++
++        this._wiredSection = new PopupMenu.PopupMenuSection();
++        this._wiredItem = new PopupMenu.PopupMenuItem(_("Wired networks"), { style_class: 'popup-subtitle-menu-item', reactive: false });
++        this._wiredDevices = [ ];
++
++        this._wiredSection.addMenuItem(this._wiredItem);
++        this._wiredSection.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
++        this._wiredSection.actor.hide();
++        this._allSections.push(this._wiredSection);
++        this.menu.addMenuItem(this._wiredSection);
++
++        this._wirelessSection = new PopupMenu.PopupMenuSection();
++        this._wirelessDevices = [ ];
++        this._makeToggleItem('wireless', _("Wireless networks"));
++        this._wirelessSection.addMenuItem(this._wirelessItem);
++
++        let newAdhocWireless = new PopupMenu.PopupMenuItem(_("Create new wireless network..."));
++        newAdhocWireless.connect('activate', Lang.bind(this, function() {
++            this._nmApplet.CreateWirelessNetworkRemote();
++        }));
++        this._wirelessSection.addMenuItem(newAdhocWireless);
++
++        let newHiddenWireless = new PopupMenu.PopupMenuItem(_("Connect to hidden wireless network..."));
++        newHiddenWireless.connect('activate', Lang.bind(this, function() {
++            this._nmApplet.ConnectToHiddenNetworkRemote();
++        }));
++        this._wirelessSection.addMenuItem(newHiddenWireless);
++
++        this._wirelessSection.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
++        this._wirelessSection.actor.hide();
++        this._allSections.push(this._wirelessSection);
++        this.menu.addMenuItem(this._wirelessSection);
++
++        this._wwanSection = new PopupMenu.PopupMenuSection();
++        this._wwanDevices = [ ];
++        this._makeToggleItem('wwan', _("Mobile broadband"));
++        this._wwanSection.addMenuItem(this._wwanItem);
++        this._wwanSection.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
++
++        this._wwanSection.actor.hide();
++        this._allSections.push(this._wwanSection);
++        this.menu.addMenuItem(this._wwanSection);
++
++        // this._vpnDevice = new NMDeviceVPN();
++        // this._vpnSection = this._vpnDevice.section
++        // this._allSections.push(this._vpnSection)
++        // this.menu.addMenuItem(this._vpnSection);
++
++        this.menu.addAction(_("Network Settings"), function() {
++            Util.spawnDesktop('gnome-network-panel');
++        });
++
++        this._activeConnections = [ ];
++        this._connections = [ ];
++
++        this._mainConnection = null;
++        this._activeAccessPointUpdateId = 0;
++        this._activeAccessPoint = null;
++        this._mobileUpdateId = 0;
++        this._mobileUpdateDevice = null;
++
++        // Device types
++        this._dtypes = { };
++        this._dtypes[makeClassKey(NMClient.DeviceEthernet.prototype)] = NMDeviceWired;
++        this._dtypes[makeClassKey(NMClient.DeviceWifi.prototype)] = NMDeviceWireless;
++        this._dtypes[makeClassKey(NMClient.GsmDevice.prototype)] = NMDeviceWWAN;
++        this._dtypes[makeClassKey(NMClient.CdmaDevice.prototype)] = NMDeviceWWAN;
++        this._dtypes[makeClassKey(NMClient.DeviceBt.prototype)] = NMDeviceBluetooth;
++        // FIXME: WWAN support (if enabled)
++
++        // Connection types
++        this._ctypes = { };
++        this._ctypes['802-11-wireless'] = 'wireless';
++        this._ctypes['802-3-ethernet'] = this._ctypes['pppoe'] = 'wired';
++        this._ctypes['bluetooth'] = this._ctypes['cdma'] = this._ctypes['gsm'] = 'wwan';
++        this._ctypes['vpn'] = 'vpn';
++
++        this._settings = NMClient.RemoteSettings.new(null);
++        this._settings.connect('connections-read', Lang.bind(this, function() {
++            this._read_connections();
++            this._read_devices();
++            this._sync_nm_state();
++
++            // Connect to signals late so that early signals don't find in inconsistent state
++            this._client.connect('notify::manager-running', Lang.bind(this, this._sync_nm_state));
++            this._client.connect('notify::networking-enabled', Lang.bind(this, this._sync_nm_state));
++            this._client.connect('notify::state', Lang.bind(this, this._sync_nm_state));
++            this._client.connect('notify::active-connections', Lang.bind(this, this._update_icon));
++            this._client.connect('device-added', Lang.bind(this, this._device_added));
++            this._client.connect('device-removed', Lang.bind(this, this._device_removed));
++            this._settings.connect('new-connection', Lang.bind(this, this._new_connection));
++        }));
++        //this._sync_nm_state();
++    },
++
++    _ensureSource: function() {
++        if (!this._source) {
++            this._source = new MessageTray.Source(_("Network Manager"));
++            let icon = new St.Icon({ icon_name: 'network-transmit-receive',
++                                     icon_type: St.IconType.SYMBOLIC,
++                                     icon_size: this._source.ICON_SIZE
++                                   });
++            this._source._setSummaryIcon(icon);
++            this._source._destroyId = this._source.connect('destroy', Lang.bind(this, function() {
++                this._source.disconnect(this._source._destroyId);
++                this._source = null;
++            }));
++            Main.messageTray.add(this._source);
++        }
++    },
++
++    _makeToggleItem: function(type, title) {
++        let enabledKey = type + '_enabled';
++        let hardwareKey = type + '_hardware_enabled';
++        let devicesKey = '_' + type + 'Devices';
++        let setEnabledFunc = type + '_set_enabled';
++
++        let item = new PopupMenu.PopupSwitchMenuItem(title, false, { style_class: 'popup-subtitle-menu-item' });
++        item.connect('toggled', Lang.bind(this, function(item, state) {
++            this._client[setEnabledFunc](state);
++        }));
++
++        let handler = Lang.bind(this, function() {
++            let software = this._client[enabledKey];
++            let hardware = this._client[hardwareKey];
++
++            let enabled = software && hardware;
++            item.setToggleState(enabled);
++            item.actor.reactive = hardware;
++            item.actor.can_focus = hardware;
++
++            let devices = this[devicesKey];
++            for (let i = 0; i < devices.length; i++) {
++                if (enabled) {
++                    if (devices.length > 1)
++                        devices[i].titleItem.actor.show();
++                    else
++                        devices[i].titleItem.actor.hide();
++                    devices[i].section.actor.show();
++                } else {
++                    devices[i].titleItem.actor.hide();
++                    devices[i].section.actor.hide();
++                }
++            }
++        });
++
++        this._client.connect('notify::' + type + '-enabled', handler);
++        this._client.connect('notify::' + type + 'hardware-enabled', handler);
++        this['_' + type + 'Item'] = item;
++        handler();
++    },
++
++    _read_devices: function() {
++        let devices = this._client.get_devices();
++        for (let i = 0; i < devices.length; ++i) {
++            this._device_added(this._client, devices[i]);
++        }
++    },
++
++    _device_added: function(client, device) {
++        let objKey = makeClassKey(device);
++        let wrapperClass = this._dtypes[objKey];
++        if (wrapperClass) {
++            // XXX: check what nm-applet does here
++            device._description = device.get_product();
++
++            let wrapper = new wrapperClass(this._client, device, this._connections);
++            wrapper._networkLostId = wrapper.connect('network-lost', Lang.bind(this, function() {
++                this._ensureSource();
++                let icon = new St.Icon({ icon_name: 'network-offline',
++                                         icon_type: St.IconType.SYMBOLIC,
++                                         icon_size: this._source.ICON_SIZE
++                                       });
++                let notification = new MessageTray.Notification(this._source,
++                                                                _("Connectivity lost"),
++                                                                _("You're no longer connected to the network"),
++                                                                { icon: icon });
++                this._source.notify(notification);
++            }));
++            wrapper._activationFailedId = wrapper.connect('activation-failed', Lang.bind(this, function(wrapper, reason) {
++                this._ensureSource();
++                let icon = new St.Icon({ icon_name: 'network-error',
++                                         icon_type: St.IconType.SYMBOLIC,
++                                         icon_size: this._source.ICON_SIZE,
++                                       });
++                let banner;
++                // XXX: nm-applet has no special text depending on reason
++                // but I'm not sure of this generic message
++                let notification = new MessageTray.Notification(this._source,
++                                                                _("Connection failed"),
++                                                                _("Activation of network connection failed"),
++                                                                { icon: icon });
++                this._source.notify(notification);
++            }));
++            let section = this['_' + wrapper.category + 'Section'];
++            let devices = this['_' + wrapper.category + 'Devices'];
++
++            section.addMenuItem(wrapper.section, 1);
++            section.addMenuItem(wrapper.titleItem, 1);
++            devices.push(wrapper);
++
++            // sync the visibility of titleItems
++            for (let i = 0; i < devices.length; i++) {
++                if (devices.length > 1)
++                    devices[i].titleItem.actor.show();
++                else
++                    devices[i].titleItem.actor.hide();
++            }
++        } else
++            log('Invalid network device class, is ' + objKey);
++    },
++
++    _device_removed: function(client, device) {
++        if (!device._delegate) {
++            log('Removing a network device that was not added (race condition?)');
++            return;
++        }
++
++        let wrapper = device._delegate;
++        wrapper.titleItem.destroy();
++        wrapper.section.destroy();
++
++        let section = this['_' + wrapper.category + 'Section'];
++        let devices = this['_' + wrapper.category + 'Devices'];
++
++        let pos = devices.indexOf(wrapper);
++        devices.splice(pos, 1);
++
++        // sync the visibility of titleItems
++        for (let i = 0; i < devices.length; i++) {
++            if (devices.length > 1)
++                devices[i].titleItem.show();
++            else
++                devices[i].titleItem.hide();
++        }
++    },
++
++    _sync_active_connections: function() {
++        let closedConnections = [ ];
++        let newActiveConnections = this._client.get_active_connections() || [ ];
++        for (let i = 0; i < this._activeConnections.length; i++) {
++            let a = this._activeConnections[i];
++            if (newActiveConnections.indexOf(a) == -1) // connection is removed
++                closedConnections.push(a);
++        }
++
++        for (let i = 0; i < closedConnections.length; i++) {
++            let active = closedConnections[i];
++            if (active._connection)
++                active._connection._active = null;
++            if (active._primaryDevice)
++                active._primaryDevice.setActiveConnection(null);
++            if (active._notifyStateId)
++                active.disconnect(active._notifyStateId);
++            if (active._inited) {
++                active.disconnect(active._notifyDefaultId);
++                active.disconnect(active._notifyDefault6Id);
++                active._inited = false;
++            }
++        }
++
++        this._activeConnections = newActiveConnections;
++        this._mainConnection = null;
++        let activating = null;
++        let default_ip4 = null;
++        let default_ip6 = null;
++        for (let i = 0; i < this._activeConnections.length; i++) {
++            let a = this._activeConnections[i];
++
++            if (!a._inited) {
++                a._notifyDefaultId = a.connect('notify::default', Lang.bind(this, this._update_icon));
++                a._notifyDefault6Id = a.connect('notify::default6', Lang.bind(this, this._update_icon));
++                if (a.state == NetworkManager.ActiveConnectionState.ACTIVATING) // prepare to notify to the user
++                    a._notifyStateId = a.connect('notify::state', Lang.bind(this, this._notify_active_connection));
++
++                a._inited = true;
++            }
++
++            if (!a._connection) {
++                a._connection = this._settings.get_connection_by_path(a.connection);
++
++                if (a._connection) {
++                    a._type = a._connection._type;
++                    a._section = this._ctypes[a._type];
++                } else {
++                    a._connection = null;
++                    a._type = null;
++                    log('Cannot find connection for active (or connection cannot be read)');
++                }
++            }
++
++            if (a._connection)
++                a._connection._active = this;
++
++            if (a['default'])
++                default_ip4 = a;
++            if (a.default6)
++                default_ip6 = a;
++
++            if (a.state == NetworkManager.ActiveConnectionState.ACTIVATING) {
++                activating = a;
++
++                // don't set activating connections to devices, NMDevice:state-changed
++                // should take care of rebuilding the menu
++                continue;
++            }
++
++            if (!a._primaryDevice) {
++                if (a._type != 'vpn') {
++                    // find a good device to be considered primary
++                    // XXX: check what nm-applet does here
++                    a._primaryDevice = null;
++                    let devices = a.get_devices();
++                    for (let j = 0; j < devices.length; j++) {
++                        let d = devices[j];
++                        if (d._delegate) {
++                            a._primaryDevice = d._delegate;
++                            break;
++                        }
++                    }
++                } else
++                    a._primaryDevice = this._vpnDevice;
++
++                if (a._primaryDevice)
++                    a._primaryDevice.setActiveConnection(a);
++            }
++        }
++
++        if (activating)
++            this._mainConnection = activating;
++        else if (default_ip4)
++            this._mainConnection = default_ip4;
++        else
++            this._mainConnection = default_ip6;
++    },
++
++    _notify_active_connection: function(active) {
++        if (active.state == NetworkManager.ActiveConnectionState.ACTIVE) {
++            this._ensureSource();
++
++            let icon;
++            let banner;
++            switch (active._type) {
++            case 'gsm':
++            case 'cdma':
++            case 'bluetooth':
++                icon = 'network-cellular-signal-excellent';
++                banner = _("You're now connected to mobile broadband connection '%s'").format(active._connection._name);
++                break;
++            case '802-11-wireless':
++                icon = 'network-wireless-signal-excellent';
++                banner = _("You're now connected to wireless network '%s'").format(active._connection._name);
++                break;
++            case '802-3-ethernet':
++            case 'pppoe':
++                icon = 'network-wired';
++                banner = _("You're now connected to wired network '%s'").format(active._connection._name);
++                break;
++            default:
++                // a fallback for a generic 'connected' icon
++                icon = 'network-transmit-receive';
++                banner = _("You're now connected to '%s'").format(active._connection._name);
++            }
++
++            let iconActor = new St.Icon({ icon_name: icon,
++                                          con_type: St.IconType.SYMBOLIC,
++                                          icon_size: this._source.ICON_SIZE
++                                        });
++            let notification = new MessageTray.Notification(this._source,
++                                                            _("Connection estabilished"),
++                                                            banner,
++                                                            { icon: iconActor });
++            this._source.notify(notification);
++
++            active.disconnect(active._stateChangeId);
++            active._stateChangeId = 0;
++        }
++
++        this._sync_nm_state();
++    },
++
++    _read_connections: function() {
++        let connections = this._settings.list_connections();
++        for (let i = 0; i < connections.length; i++) {
++            let connection = connections[i];
++            if (connection._uuid) {
++                log('Connection was already seen, when reading the connections for the first time (race condition?)');
++                continue;
++            }
++            connection.connect('removed', Lang.bind(this, this._connection_removed));
++            // we don't connect to 'updated' because GJS currently cannot deliver it
++            // (it needs to type overrides from GIR)
++            //connection.connect('updated', Lang.bind(this, this._update_connection));
++
++            let connectionSettings = connection.get_setting_by_name('connection');
++            connection._type = connectionSettings.type;
++            connection._section = this._ctypes[connection._type];
++            connection._name = connectionSettings.id;
++            connection._uuid = connectionSettings.uuid;
++            this._connections.push(connection);
++        }
++    },
++
++    _new_connection: function(settings, connection) {
++        if (connection._uuid) {
++            log('Connection was already seen, not adding again...');
++            return;
++        }
++
++        connection.connect('removed', Lang.bind(this, this._connection_removed));
++        //connection.connect('updated', Lang.bind(this, this._update_connection));
++
++        let connectionSettings = connection.get_setting_by_name('connection');
++        connection._type = connectionSettings.type;
++        connection._section = this._ctypes[connection._type];
++        connection._name = connectionSettings.id;
++        connection._uuid = connectionSettings.uuid;
++        this._connections.push(connection);
++
++        this._update_icon();
++    },
++
++    _connection_removed: function(connection) {
++        let pos = this._connections.indexOf(connection);
++        if (pos != -1)
++            this._connections.splice(connection);
++
++        if (!connection._ever_added)
++            return;
++
++        let section = connection._section;
++        let devices = this['_' + section + 'Devices'];
++        for (let i = 0; i < devices.length; i++)
++            devices[i].removeConnection(connection);
++    },
++
++    _update_connection: function(connection) {
++        this._connection_removed(connection);
++
++        let connectionSettings = connection.get_setting_by_name('connection');
++        connection._type = connectionSettings.type;
++        connection._section = this._ctypes[connection._type];
++        connection._name = connectionSettings.id;
++        connection._uuid = connectionSettings.uuid;
++
++        let section = connection._section;
++        let devices = this['_' + section + 'Devices'];
++        for (let i = 0; i < devices.length; i++) {
++            if (devices[i].connectionValid(connection)) {
++                devices[i].addConnection(connection);
++                connection._ever_added = true;
++            }
++        }
++    },
++
++    _hideAll: function() {
++        for (let i = 0; i < this._allSections.length; i++) {
++            let item = this._allSections[i];
++            item.actor.hide();
++        }
++    },
++
++    _showNormal: function() {
++        this._statusSection.actor.hide();
++
++        if (this._wiredDevices.length > 0)
++            this._wiredSection.actor.show();
++
++        if (this._wirelessDevices.length > 0)
++            this._wirelessSection.actor.show();
++
++        if (this._wwanDevices.length > 0)
++            this._wwanSection.actor.show();
++
++        // this._vpnSection.actor.show();
++    },
++
++    _sync_nm_state: function() {
++        if (!this._client.manager_running) {
++            log('NetworkManager is not running, hiding...');
++            this.menu.close();
++            this.actor.hide();
++            return;
++        } else
++            this.actor.show();
++
++        if (!this._client.networking_enabled) {
++            this.setIcon('network-offline');
++            this._hideAll();
++            this._statusItem.label.text = _("Networking is disabled");
++            this._statusSection.actor.show();
++            return;
++        }
++
++        this._showNormal();
++        this._update_icon();
++    },
++
++    _update_icon: function() {
++        this._sync_active_connections();
++        let mc = this._mainConnection;
++        let hasApIcon = false;
++        let hasMobileIcon = false;
++
++        switch (this._client.state) {
++        case NetworkManager.State.DISCONNECTED:
++            this.setIcon('network-offline');
++            break;
++        case NetworkManager.State.CONNECTING:
++            if (!mc || mc.state != NetworkManager.ActiveConnectionState.ACTIVATING) {
++                log('NetworkManager is connecting, but we have no ActiveConnection activating');
++                break;
++            }
++            switch (mc._type) {
++            case 'gsm':
++            case 'cdma':
++            case 'bluetooth':
++                this.setIcon('network-cellular-acquiring');
++                break;
++            case '802-11-wireless':
++                this.setIcon('network-wireless-acquiring');
++                break;
++            case '802-3-ethernet':
++            case 'pppoe':
++                this.setIcon('network-wired-acquiring');
++                break;
++            default:
++                this.setIcon('network-error');
++                log ('Invalid active connection type ' + mc._type);
++            }
++            break;
++        case NetworkManager.State.CONNECTED_LOCAL:
++        case NetworkManager.State.CONNECTED_SITE:
++        case NetworkManager.State.CONNECTED_GLOBAL:
++            if (!mc) {
++                log('NetworkManager is connected, but reports no active connection');
++                break;
++            }
++            let dev;
++            switch (mc._type) {
++            case '802-11-wireless':
++                dev = mc._primaryDevice;
++                if (dev) {
++                    let ap = dev.device.active_access_point;
++                    let mode = dev.device.mode;
++                    if (!ap) {
++                        if (mode != NetworkManager['80211Mode'].ADHOC) {
++                            log ('An active wireless connection, in infrastructure mode, involves no access point?');
++                            break;
++                        }
++                        this.setIcon('network-wireless-connected');
++                    } else {
++                        if (this._accessPointUpdateId && this._activeAccessPoint != ap) {
++                            this._activeAccessPoint.disconnect(this._accessPointUpdateId);
++                            this._activeAccessPoint = ap;
++                            this._activeAccessPointUpdateId = ap.connect('notify::strength', Lang.bind(function() {
++                                this.setIcon('network-wireless-signal-' + signalToIcon(ap.strength));
++                            }));
++                        }
++                        this.setIcon('network-wireless-signal-' + signalToIcon(ap.strength));
++                        hasApIcon = true;
++                    }
++                    break;
++                } else {
++                    log ('Active connection with no primary device?');
++                    break;
++                }
++            case '802-3-ethernet':
++            case 'pppoe':
++            case 'serial':
++                this.setIcon('network-wired-symbolic');
++                break;
++            case 'bluetooth':
++                // XXX: NetworkManager does not give us signal for bluetooth
++                this.setIcon('network-cellular-signal-excellent');
++                break;
++            case 'cdma':
++            case 'gsm':
++                dev = mc._primaryDevice;
++                if (this._mobileUpdateId && this._mobileUpdateDevice != dev) {
++                    this._mobileUpdateDevice.disconnect(this._mobileUpdateId);
++                    this._mobileUpdateDevice = dev.mobileDevice;
++                    this._mobileUpdateId = dev.mobileDevice.connect('notify::signal-quality', Lang.bind(this, function() {
++                        this.setIcon('network-cellular-signal-' + signalToIcon(dev.mobileDevice.signal_quality));
++                    }));
++                }
++                this.setIcon('network-cellular-signal-' + signalToIcon(dev.mobileDevice.signal_quality));
++                hasMobileIcon = true;
++                break;
++            case 'vpn':
++                this.setIcon('network-vpn');
++                break;
++            default:
++                log('Invalid active connection type ' + mc._type);
++                this.setIcon('network-error');
++                break;
++            }
++            break;
++        default:
++            log('NetworkManager is in an invalid state: ' + this._client.state);
++        }
++
++        // cleanup stale signal connections
++
++        if (!hasApIcon && this._activeAccessPointUpdateId) {
++            this._activeAccessPoint.disconnect(this._activeAccessPointUpdateId);
++            this._activeAccessPoint = null;
++            this._activeAccessPointUpdateId = 0;
++        }
++        if (!hasMobileIcon && this._mobileUpdateId) {
++            this._mobileUpdateDevice.disconnect(this._mobileUpdateId);
++            this._mobileUpdateDevice = null;
++            this._mobileUpdateId = 0;
++        }
++    }
++};
+diff --git a/tools/build/gnome-shell.modules b/tools/build/gnome-shell.modules
+index e8b5493..b14fd53 100644
+--- a/tools/build/gnome-shell.modules
++++ b/tools/build/gnome-shell.modules
+@@ -9,6 +9,8 @@
+       href="git://git.gnome.org/"/>
+   <repository type="git" name="git.moblin.org"
+       href="git://git.moblin.org"/>
++  <repository type="git" name="anongit.freedesktop.org"
++      href="git://anongit.freedesktop.org"/>
+   <repository type="tarball" name="cairo.org"
+       href="http://cairographics.org/"/>
+   <repository type="tarball" name="0pointer.de"
+@@ -237,6 +239,7 @@
+ 	<dep package="gnome-settings-daemon"/>
+ 	<dep package="gnome-bluetooth"/>
+         <dep package="telepathy-glib"/>
++        <dep package="NetworkManager"/>
+     </dependencies>
+   </autotools>
+ 
+@@ -255,6 +258,7 @@
+       <dep package="gnome-themes-standard"/>
+       <dep package="gnome-shell"/>
+       <dep package="gnome-power-manager"/>
++      <dep package="network-manager-applet"/>
+     </dependencies>
+   </metamodule>
+ 
+@@ -315,4 +319,19 @@
+     </dependencies>
+ </autotools>
+ 
++  <autotools id="NetworkManager" autogenargs="--enable-introspection">
++    <branch repo="anongit.freedesktop.org" module="NetworkManager/NetworkManager.git" checkoutdir="NetworkManager" />
++    <dependencies>
++      <dep package="glib"/>
++    </dependencies>
++  </autotools>
++
++  <autotools id="network-manager-applet">
++    <branch repo="git.gnome.org" module="network-manager-applet" />
++    <dependencies>
++      <dep package="glib"/>
++      <dep package="gtk3"/>
++      <dep package="libnotify"/>
++    </dependencies>
++  </autotools>
+ </moduleset>
+-- 
+1.7.4
\ No newline at end of file

diff --git a/gnome-base/gnome-shell/gnome-shell-9999.ebuild b/gnome-base/gnome-shell/gnome-shell-9999.ebuild
index 8a0a717..7f31f64 100644
--- a/gnome-base/gnome-shell/gnome-shell-9999.ebuild
+++ b/gnome-base/gnome-shell/gnome-shell-9999.ebuild
@@ -7,7 +7,7 @@ GCONF_DEBUG="no"
 GNOME2_LA_PUNT="yes"
 PYTHON_DEPEND="2:2.5"
 
-inherit autotools gnome2 python
+inherit eutils gnome2 python
 
 DESCRIPTION="Provides core UI functions for the GNOME 3 desktop"
 HOMEPAGE="http://live.gnome.org/GnomeShell"
@@ -47,7 +47,8 @@ COMMON_DEPEND=">=dev-libs/glib-2.25.9
 	>=media-libs/gst-plugins-base-0.10.16
 	media-libs/libcanberra
 	media-sound/pulseaudio
-	net-wireless/gnome-bluetooth[introspection]
+	>=net-misc/networkmanager-9999
+	>=net-wireless/gnome-bluetooth-2.90.0[introspection]
 
 	x11-libs/startup-notification
 	x11-libs/libXfixes
@@ -56,13 +57,15 @@ COMMON_DEPEND=">=dev-libs/glib-2.25.9
 
 	dev-python/dbus-python
 	dev-python/gconf-python"
-# Runtime-only deps are probably incomplete and approximate
+# Runtime-only deps are probably incomplete and approximate.
+# nm-applet is only needed temporarily for the secrets and wireless dialogs.
 RDEPEND="${COMMON_DEPEND}
 	x11-libs/gdk-pixbuf[introspection]
 	>=gnome-base/dconf-0.4.1
 	>=gnome-base/gnome-settings-daemon-2.91
 	>=gnome-base/gnome-control-center-2.91
-	>=gnome-base/libgnomekbd-2.91.4[introspection]"
+	>=gnome-base/libgnomekbd-2.91.4[introspection]
+	>=gnome-extra/nm-applet-9999"
 DEPEND="${COMMON_DEPEND}
 	sys-devel/gettext
 	>=dev-util/pkgconfig-0.22
@@ -72,3 +75,15 @@ DOCS="AUTHORS README"
 # Don't error out on warnings
 G2CONF="--enable-compile-warnings=maximum
 --disable-schemas-compile"
+
+src_prepare() {
+	# See https://bugzilla.gnome.org/show_bug.cgi?id=621707"
+	ewarn "Adding support for the experimental NetworkManager applet."
+	ewarn "This needs the latest NetworkManager & nm-applet trunk."
+	ewarn "Report bugs about this to 'nirbheek' on #gentoo-desktop @ FreeNode."
+	epatch "${FILESDIR}/${PN}-nm-1.patch"
+	epatch "${FILESDIR}/${PN}-nm-2.patch"
+	epatch "${FILESDIR}/${PN}-nm-3.patch"
+
+	gnome2_src_prepare
+}

diff --git a/net-misc/networkmanager/files/networkmanager-introspection-fixes.patch b/net-misc/networkmanager/files/networkmanager-introspection-fixes.patch
new file mode 100644
index 0000000..2c5befc
--- /dev/null
+++ b/net-misc/networkmanager/files/networkmanager-introspection-fixes.patch
@@ -0,0 +1,206 @@
+From dbd3c269d04413deb79a72f688af77ea299d2205 Mon Sep 17 00:00:00 2001
+From: Giovanni Campagna <gcampagna@src.gnome.org>
+Date: Sat, 11 Dec 2010 18:05:30 +0100
+Subject: [PATCH] More GObjectIntrospection fixes
+
+Fix some annotations and add the necessary ones for new functions.
+
+https://bugzilla.gnome.org/show_bug.cgi?id=637032
+---
+ libnm-glib/nm-client.c            |    5 +++--
+ libnm-glib/nm-dhcp4-config.c      |    2 ++
+ libnm-glib/nm-dhcp6-config.c      |    2 ++
+ libnm-glib/nm-remote-connection.c |    9 +++++++++
+ libnm-glib/nm-secret-agent.c      |   37 +++++++++++++++++++++++++++++++++++++
+ libnm-util/nm-connection.c        |   17 +++++++++--------
+ libnm-util/nm-setting-vpn.h       |    2 --
+ 7 files changed, 62 insertions(+), 12 deletions(-)
+
+diff --git a/libnm-glib/nm-client.c b/libnm-glib/nm-client.c
+index 4e725cf..bab86a9 100644
+--- a/libnm-glib/nm-client.c
++++ b/libnm-glib/nm-client.c
+@@ -1152,8 +1152,9 @@ activate_cb (DBusGProxy *proxy,
+  * @client: a #NMClient
+  * @connection_path: the connection's DBus path
+  * @device: the #NMDevice
+- * @specific_object: the device specific object (currently used only for
+- * activating wireless devices and should be the #NMAccessPoint<!-- -->'s path.
++ * @specific_object: (allow-none): the device specific object (currently
++ *   used only for activating wireless devices and should be the
++ *   #NMAccessPoint<!-- -->'s path).
+  * @callback: (scope async): the function to call when the call is done
+  * @user_data: user data to pass to the callback function
+  *
+diff --git a/libnm-glib/nm-dhcp4-config.c b/libnm-glib/nm-dhcp4-config.c
+index d17578a..31dfe25 100644
+--- a/libnm-glib/nm-dhcp4-config.c
++++ b/libnm-glib/nm-dhcp4-config.c
+@@ -169,6 +169,8 @@ nm_dhcp4_config_class_init (NMDHCP4ConfigClass *config_class)
+ 	 * NMDHCP4Config:options:
+ 	 *
+ 	 * The #GHashTable containing options of the configuration.
++	 *
++	 * Type: GHashTable<utf8,GValue>
+ 	 **/
+ 	g_object_class_install_property
+ 		(object_class, PROP_OPTIONS,
+diff --git a/libnm-glib/nm-dhcp6-config.c b/libnm-glib/nm-dhcp6-config.c
+index 8b85595..7e6e4f8 100644
+--- a/libnm-glib/nm-dhcp6-config.c
++++ b/libnm-glib/nm-dhcp6-config.c
+@@ -169,6 +169,8 @@ nm_dhcp6_config_class_init (NMDHCP6ConfigClass *config_class)
+ 	 * NMDHCP6Config:options:
+ 	 *
+ 	 * The #GHashTable containing options of the configuration.
++	 *
++	 * Type: GHashTable<utf8,GValue>
+ 	 **/
+ 	g_object_class_install_property
+ 		(object_class, PROP_OPTIONS,
+diff --git a/libnm-glib/nm-remote-connection.c b/libnm-glib/nm-remote-connection.c
+index 09c7112..1869a3a 100644
+--- a/libnm-glib/nm-remote-connection.c
++++ b/libnm-glib/nm-remote-connection.c
+@@ -480,6 +480,15 @@ nm_remote_connection_class_init (NMRemoteConnectionClass *remote_class)
+ 		                    G_PARAM_READABLE));
+ 
+ 	/* Signals */
++    /**
++     * NMRemoteConnection::updated:
++     * @connection: a #NMConnection
++     * @new_settings: (type GHashTable<utf8,GHashTable<utf8,GValue>>):
++     *                the updated settings
++     *
++     * This signal is emitted when a connection changes, and it is
++     * still visible to the user.
++     */
+ 	signals[UPDATED] = 
+ 		g_signal_new (NM_REMOTE_CONNECTION_UPDATED,
+ 		              G_TYPE_FROM_CLASS (remote_class),
+diff --git a/libnm-glib/nm-secret-agent.c b/libnm-glib/nm-secret-agent.c
+index 72431e2..9cc2440 100644
+--- a/libnm-glib/nm-secret-agent.c
++++ b/libnm-glib/nm-secret-agent.c
+@@ -567,6 +567,20 @@ auto_register_cb (gpointer user_data)
+ 
+ /**************************************************************/
+ 
++/**
++ * nm_secret_agent_get_secrets:
++ * @self: a #NMSecretAgent
++ * @connection: the #NMConnection for which we're asked secrets
++ * @setting_name: the name of the secret setting
++ * @hints: (array zero-terminated=1): hints to the agent
++ * @flags:
++ * @callback: (scope async): a callback, invoked when the operation is done
++ * @callback_data: (closure):
++ *
++ * Asyncronously retrieve @setting_name from @connection
++ *
++ * VFunc: get_secrets
++ */
+ void
+ nm_secret_agent_get_secrets (NMSecretAgent *self,
+                              NMConnection *connection,
+@@ -595,6 +609,18 @@ nm_secret_agent_get_secrets (NMSecretAgent *self,
+ 	                                               callback_data);
+ }
+ 
++/**
++ * nm_secret_agent_save_secrets:
++ * @self: a #NMSecretAgent
++ * @connection: a #NMConnection
++ * @callback: (scope async): a callback, invoked when the operation is done
++ * @callback_data: (closure):
++ *
++ * Asyncronously ensure that all secrets inside @connection
++ * are stored to disk.
++ *
++ * VFunc: save_secrets
++ */
+ void
+ nm_secret_agent_save_secrets (NMSecretAgent *self,
+                               NMConnection *connection,
+@@ -614,6 +640,17 @@ nm_secret_agent_save_secrets (NMSecretAgent *self,
+ 	                                                callback_data);
+ }
+ 
++/**
++ * nm_secret_agent_delete_secrets:
++ * @self: a #NMSecretAgent
++ * @connection: a #NMConnection
++ * @callback: (scope async): a callback, invoked when the operation is done
++ * @callback_data: (closure):
++ *
++ * Asyncronously remove all secret settings from @connection
++ *
++ * VFunc: delete_secrets
++ */
+ void
+ nm_secret_agent_delete_secrets (NMSecretAgent *self,
+                                 NMConnection *connection,
+diff --git a/libnm-util/nm-connection.c b/libnm-util/nm-connection.c
+index ec33907..aef1cc0 100644
+--- a/libnm-util/nm-connection.c
++++ b/libnm-util/nm-connection.c
+@@ -493,7 +493,7 @@ validate_permissions_type (GHashTable *hash, GError **error)
+ /**
+  * nm_connection_replace_settings:
+  * @connection: a #NMConnection
+- * @new_settings: (element-type utf8 GLib.HashTable): a #GHashTable of settings
++ * @new_settings: (element-type utf8 GHashTable<utf8,GValue>): a #GHashTable of settings
+  * @error: location to store error, or %NULL
+  *
+  * Returns: %TRUE if the settings were valid and added to the connection, %FALSE
+@@ -728,11 +728,12 @@ add_setting_to_list (gpointer key, gpointer data, gpointer user_data)
+ /**
+  * nm_connection_need_secrets:
+  * @connection: the #NMConnection
+- * @hints: the address of a pointer to a #GPtrArray, initialized to NULL, which
+- * on return points to an allocated #GPtrArray containing the property names of
+- * secrets of the #NMSetting which may be required; the caller owns the array
+- * and must free the each array element with g_free(), as well as the array
+- * itself with g_ptr_array_free()
++ * @hints: (out callee-allocates) (element-type utf8) (allow-none) (transfer full):
++ *   the address of a pointer to a #GPtrArray, initialized to NULL, which on
++ *   return points to an allocated #GPtrArray containing the property names of
++ *   secrets of the #NMSetting which may be required; the caller owns the array
++ *   and must free the each array element with g_free(), as well as the array
++ *   itself with g_ptr_array_free()
+  *
+  * Returns the name of the first setting object in the connection which would
+  * need secrets to make a successful connection.  The returned hints are only
+@@ -741,7 +742,7 @@ add_setting_to_list (gpointer key, gpointer data, gpointer user_data)
+  * secrets are needed.
+  *
+  * Returns: the setting name of the #NMSetting object which has invalid or
+- * missing secrets
++ *   missing secrets
+  **/
+ const char *
+ nm_connection_need_secrets (NMConnection *connection,
+@@ -821,7 +822,7 @@ nm_connection_clear_secrets (NMConnection *connection)
+  * are #GHashTables mapping string:GValue, each of which represents the
+  * properties of the #NMSetting object.
+  *
+- * Returns: (transfer full) (element-type utf8 GLib.HashTable): a new 
++ * Returns: (transfer full) (element-type utf8 GHashTable<utf8,GValue>): a new
+  * #GHashTable describing the connection, its settings, and each setting's
+  * properties.  The caller owns the hash table and must unref the hash table
+  * with g_hash_table_unref() when it is no longer needed.
+diff --git a/libnm-util/nm-setting-vpn.h b/libnm-util/nm-setting-vpn.h
+index bb20356..6ff1928 100644
+--- a/libnm-util/nm-setting-vpn.h
++++ b/libnm-util/nm-setting-vpn.h
+@@ -72,8 +72,6 @@ typedef struct {
+ } NMSettingVPNClass;
+ 
+ typedef void (*NMVPNIterFunc) (const char *key, const char *value, gpointer user_data);
+-/* For backward compatibility */
+-typedef NMVPNIterFunc VPNIterFunc;
+ 
+ GType nm_setting_vpn_get_type (void);
+ 
+-- 
+1.7.4
\ No newline at end of file

diff --git a/net-misc/networkmanager/metadata.xml b/net-misc/networkmanager/metadata.xml
new file mode 100644
index 0000000..1e6b51f
--- /dev/null
+++ b/net-misc/networkmanager/metadata.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE pkgmetadata SYSTEM "http://www.gentoo.org/dtd/metadata.dtd">
+<pkgmetadata>
+	<herd>no-herd</herd>
+	<maintainer>
+		<email>dagger@gentoo.org</email>
+		<name>Robert Piasek</name>
+	</maintainer>
+	<maintainer>
+		<email>nirbheek@gentoo.org</email>
+		<name>Nirbheek Chauhan</name>
+	</maintainer>
+        <maintainer>
+                <email>steev@gentoo.org</email>
+                <name>Stephen Klimaszewski</name>
+        </maintainer>
+	<use>
+		<flag name="dhclient">Use dhclient from <pkg>net-misc/dhcp</pkg> for getting ip.</flag>
+		<flag name="dhcpcd">Use <pkg>net-misc/dhcpcd</pkg> for getting ip.</flag>
+		<flag name="nss">Use <pkg>dev-libs/nss</pkg> for cryptography.</flag>
+		<flag name="resolvconf">Use <pkg>net-dns/openresolv</pkg> for managing DNS information</flag>
+		<flag name="connection-sharing">Use <pkg>net-dns/dnsmasq</pkg> and <pkg>net-firewall/iptables</pkg> for connection sharing </flag>
+	</use>
+</pkgmetadata>

diff --git a/net-misc/networkmanager/networkmanager-9999.ebuild b/net-misc/networkmanager/networkmanager-9999.ebuild
index e48e5e0..f0f5095 100644
--- a/net-misc/networkmanager/networkmanager-9999.ebuild
+++ b/net-misc/networkmanager/networkmanager-9999.ebuild
@@ -16,8 +16,8 @@ HOMEPAGE="http://www.gnome.org/projects/NetworkManager/"
 
 LICENSE="GPL-2"
 SLOT="0"
-IUSE="avahi bluetooth doc nss gnutls dhclient dhcpcd kernel_linux resolvconf
-connection-sharing wimax"
+IUSE="avahi bluetooth doc nss gnutls dhclient dhcpcd +introspection kernel_linux
+resolvconf connection-sharing wimax"
 if [[ ${PV} = 9999 ]]; then
 	inherit gnome2-live
 	EGIT_REPO_URI="git://anongit.freedesktop.org/${MY_PN}/${MY_PN}"
@@ -27,6 +27,7 @@ else
 	KEYWORDS="~amd64 ~arm ~ppc ~ppc64 ~x86"
 fi
 
+# gobject-introspection-0.10.2-r1 is needed due to gnome bug 642300
 RDEPEND=">=sys-apps/dbus-1.2
 	>=dev-libs/dbus-glib-0.75
 	>=net-wireless/wireless-tools-28_pre9
@@ -48,6 +49,7 @@ RDEPEND=">=sys-apps/dbus-1.2
 		dhcpcd? ( >=net-misc/dhcpcd-4.0.0_rc3 )
 		!dhcpcd? ( net-misc/dhcp ) )
 	!dhclient? ( >=net-misc/dhcpcd-4.0.0_rc3 )
+	introspection? ( >=dev-libs/gobject-introspection-0.10.2-r1 )
 	resolvconf? ( net-dns/openresolv )
 	connection-sharing? (
 		net-dns/dnsmasq
@@ -96,6 +98,7 @@ pkg_setup() {
 		--with-iptables=/sbin/iptables
 		$(use_with doc docs)
 		$(use_with resolvconf)
+		$(use_enable introspection)
 		$(use_enable wimax)"
 
 	# default is dhcpcd (if none or both are specified), ISC dchclient otherwise
@@ -127,7 +130,11 @@ src_prepare() {
 	epatch "${FILESDIR}/${PN}-0.8.2-confchanges.patch"
 	# fix shared connection wrt bug #350476
 	# fix parsing dhclient.conf wrt bug #352638
-	epatch "${FILESDIR}/${PN}-0.8.2-shared-connection.patch"
+	# FIXME: does not apply
+	#epatch "${FILESDIR}/${PN}-0.8.2-shared-connection.patch"
+
+	# https://bugzilla.gnome.org/show_bug.cgi?id=637032
+	epatch "${FILESDIR}/${PN}-introspection-fixes.patch"
 
 	gnome2_src_prepare
 }



^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2011-02-20 23:19 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-02-20 23:19 [gentoo-commits] proj/gnome:master commit in: dev-libs/gobject-introspection/files/, gnome-base/gnome-shell/, Nirbheek Chauhan

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox