File wired-connection-status.patch of Package gnome-shell.1083

diff --git a/js/ui/status/network.js b/js/ui/status/network.js
index 7deb7f4..c133fcb 100644
--- a/js/ui/status/network.js
+++ b/js/ui/status/network.js
@@ -23,6 +23,7 @@ const Util = imports.misc.util;
 
 const NMConnectionCategory = {
     INVALID: 'invalid',
+    WIRED: 'wired',
     WIRELESS: 'wireless',
     WWAN: 'wwan',
     VPN: 'vpn'
@@ -103,18 +104,21 @@ const NMConnectionItem = new Lang.Class({
         this._activeConnection = null;
         this._activeConnectionChangedId = 0;
 
+        this._buildUI();
+        this._sync();
+    },
+
+    _buildUI: function() {
         this.labelItem = new PopupMenu.PopupMenuItem('');
         this.labelItem.connect('activate', Lang.bind(this, this._toggle));
 
-        this.switchItem = new PopupMenu.PopupSwitchMenuItem(connection.get_id(), false);
-        this.switchItem.connect('toggled', Lang.bind(this, this._toggle));
-
-        this._sync();
+        this.radioItem = new PopupMenu.PopupMenuItem(_('Connect') + ": "+ this._connection.get_id(), false);
+        this.radioItem.connect('activate', Lang.bind(this, this._activate));
     },
 
     destroy: function() {
         this.labelItem.destroy();
-        this.switchItem.destroy();
+        this.radioItem.destroy();
     },
 
     getName: function() {
@@ -131,8 +135,7 @@ const NMConnectionItem = new Lang.Class({
     _sync: function() {
         let isActive = this.isActive();
         this.labelItem.label.text = isActive ? _("Turn Off") : _("Connect");
-        this.switchItem.setToggleState(isActive);
-        this.switchItem.setStatus(this._getStatus());
+        this.radioItem.setOrnament(isActive ? PopupMenu.Ornament.DOT : PopupMenu.Ornament.NONE);
         this.emit('icon-changed');
     },
 
@@ -145,8 +148,11 @@ const NMConnectionItem = new Lang.Class({
         this._sync();
     },
 
-    _getStatus: function() {
-        return null;
+    _activate: function() {
+        if (this._activeConnection == null)
+            this._section.activateConnection(this._connection);
+
+        this._sync();
     },
 
     _connectionStateChanged: function(ac, newstate, reason) {
@@ -181,11 +187,11 @@ const NMConnectionSection = new Lang.Class({
         this._connections = [];
 
         this._labelSection = new PopupMenu.PopupMenuSection();
-        this._switchSection = new PopupMenu.PopupMenuSection();
+        this._radioSection = new PopupMenu.PopupMenuSection();
 
         this.item = new PopupMenu.PopupSubMenuMenuItem('', true);
         this.item.menu.addMenuItem(this._labelSection);
-        this.item.menu.addMenuItem(this._switchSection);
+        this.item.menu.addMenuItem(this._radioSection);
 
         this.connect('icon-changed', Lang.bind(this, this._sync));
     },
@@ -197,7 +203,7 @@ const NMConnectionSection = new Lang.Class({
     _sync: function() {
         let nItems = this._connectionItems.size();
 
-        this._switchSection.actor.visible = (nItems > 1);
+        this._radioSection.actor.visible = (nItems > 1);
         this._labelSection.actor.visible = (nItems == 1);
 
         this.item.status.text = this._getStatus();
@@ -212,6 +218,10 @@ const NMConnectionSection = new Lang.Class({
             this.item.label.text = '';
     },
 
+    _getMenuIcon: function() {
+        return this.getIndicatorIcon();
+    },
+
     _getStatus: function() {
         let values = this._connectionItems.values();
         for (let i = 0; i < values.length; i++) {
@@ -266,7 +276,7 @@ const NMConnectionSection = new Lang.Class({
 
         let pos = Util.insertSorted(this._connections, connection, Lang.bind(this, this._connectionSortFunction));
         this._labelSection.addMenuItem(item.labelItem, pos);
-        this._switchSection.addMenuItem(item.switchItem, pos);
+        this._radioSection.addMenuItem(item.radioItem, pos);
         this._connectionItems.set(connection.get_uuid(), item);
         this._sync();
     },
@@ -294,11 +304,17 @@ const NMConnectionDevice = new Lang.Class({
         this._settings = settings;
 
         this._autoConnectItem = this.item.menu.addAction(_("Connect"), Lang.bind(this, this._autoConnect));
+        this._deactivateItem = this._radioSection.addAction(_("Turn Off"), Lang.bind(this, this.deactivateConnection));
 
         this._stateChangedId = this._device.connect('state-changed', Lang.bind(this, this._deviceStateChanged));
         this._activeConnectionChangedId = this._device.connect('notify::active-connection', Lang.bind(this, this._activeConnectionChanged));
     },
 
+    _autoConnect: function() {
+        let connection = new NetworkManager.Connection();
+        this._client.add_and_activate_connection(connection, this._device, null, null);
+    },
+
     destroy: function() {
         if (this._stateChangedId) {
             GObject.Object.prototype.disconnect.call(this._device, this._stateChangedId);
@@ -368,6 +384,7 @@ const NMConnectionDevice = new Lang.Class({
     _sync: function() {
         let nItems = this._connectionItems.size();
         this._autoConnectItem.actor.visible = (nItems == 0);
+        this._deactivateItem.actor.visible = this._device.state > NetworkManager.DeviceState.DISCONNECTED;
         this.parent();
     },
 
@@ -379,7 +396,7 @@ const NMConnectionDevice = new Lang.Class({
         case NetworkManager.DeviceState.DISCONNECTED:
             return _("Off");
         case NetworkManager.DeviceState.ACTIVATED:
-            return this.parent();
+            return _("Connected");
         case NetworkManager.DeviceState.UNMANAGED:
             /* Translators: this is for network devices that are physically present but are not
                under NetworkManager's control (and thus cannot be used in the menu) */
@@ -416,6 +433,57 @@ const NMConnectionDevice = new Lang.Class({
     },
 });
 
+const NMDeviceWired = new Lang.Class({
+    Name: 'NMDeviceWired',
+    Extends: NMConnectionDevice,
+    category: NMConnectionCategory.WIRED,
+
+    _init: function(client, device, settings) {
+        this.parent(client, device, settings);
+
+        this.item.menu.addMenuItem(createSettingsAction(_("Wired Settings") + "...", device));
+    },
+
+    _hasCarrier: function() {
+        if (this._device instanceof NMClient.DeviceEthernet)
+            return this._device.carrier;
+        else
+            return true;
+    },
+
+    _sync: function() {
+        // Deactivate the item instead of hiding it when the cable is
+        // unplugged., so that the user will know the exact reason.
+        this.item.setSensitive(this._hasCarrier());
+        this.parent();
+    },
+
+    // SLE: overrides the parent one so that the "unplugged" state can be more
+    // accurately displayed. See NMConnectionDevice::_getStatus for details.
+    _getStatus: function() {
+        let statusStr = this.parent();
+        if ( statusStr === _('unavailable') ){
+            return _('cable unplugged');
+        }
+
+        return statusStr;
+    },
+
+    getIndicatorIcon: function() {
+        if (this._device.active_connection) {
+            let state = this._device.active_connection.state;
+
+            if (state == NetworkManager.ActiveConnectionState.ACTIVATING)
+                return 'network-wired-acquiring-symbolic';
+            else if (state == NetworkManager.ActiveConnectionState.ACTIVATED)
+                return 'network-wired-symbolic';
+            else
+                return 'network-wired-disconnected-symbolic';
+        } else
+            return 'network-wired-disconnected-symbolic';
+    }
+});
+
 const NMDeviceModem = new Lang.Class({
     Name: 'NMDeviceModem',
     Extends: NMConnectionDevice,
@@ -478,28 +546,20 @@ const NMDeviceModem = new Lang.Class({
             return this.parent();
     },
 
-    _getMenuIcon: function() {
-        if (this._device.active_connection)
-            return this.getIndicatorIcon();
-        else
+    getIndicatorIcon: function() {
+        if (this._device.active_connection) {
+            if (this._device.active_connection.state == NetworkManager.ActiveConnectionState.ACTIVATING)
+                return 'network-cellular-acquiring-symbolic';
+
+            return this._getSignalIcon();
+        } else {
             return 'network-cellular-signal-none-symbolic';
+        }
     },
 
     _getSignalIcon: function() {
         return 'network-cellular-signal-' + signalToIcon(this._mobileDevice.signal_quality) + '-symbolic';
     },
-
-    getIndicatorIcon: function() {
-        if (this._device.active_connection.state == NetworkManager.ActiveConnectionState.ACTIVATING)
-            return 'network-cellular-acquiring-symbolic';
-
-        if (!this._mobileDevice) {
-            // this can happen for bluetooth in PAN mode
-            return 'network-cellular-connected-symbolic';
-        }
-
-        return this._getSignalIcon();
-    }
 });
 
 const NMDeviceBluetooth = new Lang.Class({
@@ -532,21 +592,18 @@ const NMDeviceBluetooth = new Lang.Class({
         return true;
     },
 
-    _getMenuIcon: function() {
-        if (this._device.active_connection)
-            return this.getIndicatorIcon();
-        else
-            return 'network-cellular-signal-none-symbolic';
-    },
-
     getIndicatorIcon: function() {
-        let state = this._device.active_connection.state;
-        if (state == NetworkManager.ActiveConnectionState.ACTIVATING)
-            return 'network-cellular-acquiring-symbolic';
-        else if (state == NetworkManager.ActiveConnectionState.ACTIVATED)
-            return 'network-cellular-connected-symbolic';
-        else
+        if (this._device.active_connection) {
+            let state = this._device.active_connection.state;
+            if (state == NetworkManager.ActiveConnectionState.ACTIVATING)
+                return 'network-cellular-acquiring-symbolic';
+            else if (state == NetworkManager.ActiveConnectionState.ACTIVATED)
+                return 'network-cellular-connected-symbolic';
+            else
+                return 'network-cellular-signal-none-symbolic';
+        } else {
             return 'network-cellular-signal-none-symbolic';
+        }
     }
 });
 
@@ -1147,8 +1204,9 @@ const NMDeviceWireless = new Lang.Class({
     },
 
     getIndicatorIcon: function() {
-        if (this._device.state >= NetworkManager.DeviceState.PREPARE &&
-            this._device.state < NetworkManager.DeviceState.ACTIVATED)
+        if (this._device.state < NetworkManager.DeviceState.PREPARE)
+            return 'network-wireless-disconnected-symbolic';
+        if (this._device.state < NetworkManager.DeviceState.ACTIVATED)
             return 'network-wireless-acquiring-symbolic';
 
         let ap = this._device.active_access_point;
@@ -1175,6 +1233,22 @@ const NMVPNConnectionItem = new Lang.Class({
         return this._activeConnection.vpn_state != NetworkManager.VPNConnectionState.DISCONNECTED;
     },
 
+    _buildUI: function() {
+        this.labelItem = new PopupMenu.PopupMenuItem('');
+        this.labelItem.connect('activate', Lang.bind(this, this._toggle));
+
+        this.radioItem = new PopupMenu.PopupSwitchMenuItem(this._connection.get_id(), false);
+        this.radioItem.connect('toggled', Lang.bind(this, this._toggle));
+    },
+
+    _sync: function() {
+        let isActive = this.isActive();
+        this.labelItem.label.text = isActive ? _("Turn Off") : this._section.getConnectLabel();
+        this.radioItem.setToggleState(isActive);
+        this.radioItem.setStatus(this._getStatus());
+        this.emit('icon-changed');
+    },
+
     _getStatus: function() {
         if (this._activeConnection == null)
             return null;
@@ -1308,6 +1382,7 @@ const NMApplet = new Lang.Class({
 
         // Device types
         this._dtypes = { };
+        this._dtypes[NetworkManager.DeviceType.ETHERNET] = NMDeviceWired;
         this._dtypes[NetworkManager.DeviceType.WIFI] = NMDeviceWireless;
         this._dtypes[NetworkManager.DeviceType.MODEM] = NMDeviceModem;
         this._dtypes[NetworkManager.DeviceType.BT] = NMDeviceBluetooth;
@@ -1315,6 +1390,7 @@ const NMApplet = new Lang.Class({
 
         // Connection types
         this._ctypes = { };
+        this._ctypes[NetworkManager.SETTING_WIRED_SETTING_NAME] = NMConnectionCategory.WIRED;
         this._ctypes[NetworkManager.SETTING_WIRELESS_SETTING_NAME] = NMConnectionCategory.WIRELESS;
         this._ctypes[NetworkManager.SETTING_BLUETOOTH_SETTING_NAME] = NMConnectionCategory.WWAN;
         this._ctypes[NetworkManager.SETTING_CDMA_SETTING_NAME] = NMConnectionCategory.WWAN;
@@ -1337,6 +1413,15 @@ const NMApplet = new Lang.Class({
         this._tryLateInit();
     },
 
+    _createDeviceCategory: function() {
+        let category = {
+            section: new PopupMenu.PopupMenuSection(),
+            devices: [ ],
+        };
+        this.menu.addMenuItem(category.section);
+        return category;
+    },
+
     _tryLateInit: function() {
         if (!this._client || !this._settings)
             return;
@@ -1365,17 +1450,9 @@ const NMApplet = new Lang.Class({
         this._nmDevices = [];
         this._devices = { };
 
-        this._devices.wireless = {
-            section: new PopupMenu.PopupMenuSection(),
-            devices: [ ],
-        };
-        this.menu.addMenuItem(this._devices.wireless.section);
-
-        this._devices.wwan = {
-            section: new PopupMenu.PopupMenuSection(),
-            devices: [ ],
-        };
-        this.menu.addMenuItem(this._devices.wwan.section);
+        this._devices.wired = this._createDeviceCategory();
+        this._devices.wireless = this._createDeviceCategory();
+        this._devices.wwan = this._createDeviceCategory();
 
         this._vpnSection = new NMVPNSection(this._client);
         this._vpnSection.connect('activation-failed', Lang.bind(this, this._onActivationFailed));
openSUSE Build Service is sponsored by