1
1
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
2
const ByteArray = imports.byteArray;
3
2
const GLib = imports.gi.GLib;
4
3
const GObject = imports.gi.GObject;
4
const Gio = imports.gi.Gio;
5
5
const Lang = imports.lang;
6
const Mainloop = imports.mainloop;
7
6
const NetworkManager = imports.gi.NetworkManager;
8
7
const NMClient = imports.gi.NMClient;
9
const Shell = imports.gi.Shell;
10
8
const Signals = imports.signals;
11
9
const St = imports.gi.St;
124
122
this._secureIcon = new St.Icon({ style_class: 'popup-menu-icon' });
125
123
if (this.bestAP._secType != NMAccessPointSecurity.UNKNOWN &&
126
124
this.bestAP._secType != NMAccessPointSecurity.NONE)
127
this._secureIcon.icon_name = 'network-wireless-encrypted';
125
this._secureIcon.icon_name = 'network-wireless-encrypted-symbolic';
128
126
this._icons.add_actor(this._secureIcon);
136
134
_getIcon: function() {
137
135
if (this.bestAP.mode == NM80211Mode.ADHOC)
138
return 'network-workgroup';
136
return 'network-workgroup-symbolic';
140
return 'network-wireless-signal-' + signalToIcon(this.bestAP.strength);
138
return 'network-wireless-signal-' + signalToIcon(this.bestAP.strength) + '-symbolic';
171
169
let newState = this._switch.state;
173
// Immediately reset the switch to false, it will be updated appropriately
174
// by state-changed signals in devices (but fixes the VPN not being in sync
175
// if the ActiveConnection object is never seen by libnm-glib)
176
this._switch.setToggleState(false);
179
this._device.activate();
173
ok = this._device.activate();
181
this._device.deactivate();
175
ok = this._device.deactivate();
178
this._switch.setToggleState(false);
275
272
if (this.device) {
276
273
this.statusItem = new PopupMenu.PopupSwitchMenuItem(this._getDescription(), this.connected, { style_class: 'popup-subtitle-menu-item' });
277
274
this._statusChanged = this.statusItem.connect('toggled', Lang.bind(this, function(item, state) {
277
ok = this.activate();
282
this.emit('enabled-changed');
279
ok = this.deactivate();
282
item.setToggleState(!state);
285
285
this._updateStatusItem();
318
318
deactivate: function() {
319
319
this.device.disconnect(null);
322
323
activate: function() {
323
324
if (this._activeConnection)
327
// pick the most recently used connection and connect to that
328
// or if no connections ever set, create an automatic one
329
if (this._connections.length > 0) {
328
// If there is only one connection available, use that
329
// Otherwise, if no connection is currently configured,
330
// try automatic configuration (or summon the config dialog)
331
if (this._connections.length == 1) {
330
332
this._client.activate_connection(this._connections[0].connection, this.device, null, null);
331
} else if (this._autoConnectionName) {
332
let connection = this._createAutomaticConnection();
334
this._client.add_and_activate_connection(connection, this.device, null, null);
334
} else if (this._connections.length == 0) {
335
return this._activateAutomaticConnection();
341
_activateAutomaticConnection: function() {
342
let connection = this._createAutomaticConnection();
344
this._client.add_and_activate_connection(connection, this.device, null, null);
338
351
get connected() {
765
778
_getSignalIcon: function() {
766
return 'network-cellular-signal-' + signalToIcon(this.mobileDevice.signal_quality);
779
return 'network-cellular-signal-' + signalToIcon(this.mobileDevice.signal_quality) + '-symbolic';
769
782
_createSection: function() {
792
_createAutomaticConnection: function() {
805
_activateAutomaticConnection: function() {
793
806
// Mobile wizard is too complex for the shell UI and
794
807
// is handled by the network panel
795
808
Util.spawn(['gnome-control-center', 'network',
796
809
'connect-3g', this.device.get_path()]);
801
814
const NMDeviceBluetooth = new Lang.Class({
824
837
return connection;
840
_activateAutomaticConnection: function() {
841
// FIXME: DUN devices are configured like modems, so
842
// we need to spawn the mobile wizard
843
// but the network panel doesn't support bluetooth at the moment
844
// so we just create an empty connection and hope
845
// that this phone supports PAN
847
return this.parent();
827
850
_makeConnectionName: function(device) {
828
851
let name = device.name;
1044
1067
activate: function() {
1045
1068
if (this._activeConnection)
1046
1069
// nothing to do
1049
// among all visible networks, pick the last recently used connection
1051
let bestApObj = null;
1053
for (let i = 0; i < this._networks.length; i++) {
1054
let apObj = this._networks[i];
1055
for (let j = 0; j < apObj.connections.length; j++) {
1056
let connection = apObj.connections[j];
1057
if (connection._timestamp > bestTime) {
1059
bestTime = connection._timestamp;
1066
for (let i = 0; i < bestApObj.accessPoints.length; i++) {
1067
let ap = bestApObj.accessPoints[i];
1068
if (ap.connection_valid(best)) {
1069
this._client.activate_connection(best, this.device, ap.dbus_path, null);
1076
// XXX: what else to do?
1077
// for now, just pick a random network
1078
// (this function is called in a corner case anyway, that is, only when
1079
// the user toggles the switch and has more than one wireless device)
1080
if (this._networks.length > 0) {
1081
let connection = this._createAutomaticConnection(this._networks[0]);
1082
let accessPoints = this._networks[0].accessPoints;
1083
this._client.add_and_activate_connection(connection, this.device, accessPoints[0].dbus_path, null);
1072
// All possible policy we can have here is just broken
1073
// NM autoconnects when wifi devices are enabled, and if it
1074
// didn't, there is a good reason
1075
// User, pick a connection from the list, thank you
1087
1079
_notifySsidCb: function(accessPoint) {
1471
1463
{ reactive: false });
1473
1465
this._activeConnectionItem = new PopupMenu.PopupImageMenuItem(title,
1474
'network-wireless-connected',
1466
'network-wireless-connected-symbolic',
1475
1467
{ reactive: false });
1476
1468
this._activeConnectionItem.setShowDot(true);
1568
1560
const NMApplet = new Lang.Class({
1569
1561
Name: 'NMApplet',
1570
Extends: PanelMenu.Button,
1562
Extends: PanelMenu.SystemStatusButton,
1572
1564
_init: function() {
1573
this.parent(0.0, _('Network'));
1575
this._box = new St.BoxLayout({ name: 'networkMenu' });
1576
this.actor.add_actor (this._box);
1577
this.actor.add_style_class_name('panel-status-button');
1579
this._primaryIcon = new St.Icon({ icon_name: 'network-offline',
1580
icon_type: St.IconType.SYMBOLIC,
1581
style_class: 'system-status-icon' });
1582
this._box.add_actor(this._primaryIcon);
1584
this._secondaryIcon = new St.Icon({ icon_name: 'network-vpn',
1585
icon_type: St.IconType.SYMBOLIC,
1586
style_class: 'system-status-icon',
1588
this._box.add_actor(this._secondaryIcon);
1565
this.parent('network-offline-symbolic', _('Network'));
1567
this.secondaryIcon = this.addIcon(new Gio.ThemedIcon({ name: 'network-vpn-symbolic' }));
1568
this.secondaryIcon.hide();
1590
1570
this._client = NMClient.Client.new();
1592
1572
this._statusSection = new PopupMenu.PopupMenuSection();
1593
this._statusItem = new PopupMenu.PopupMenuItem('', { style_class: 'popup-inactive-menu-item', reactive: false });
1573
this._statusItem = new PopupMenu.PopupMenuItem('', { reactive: false });
1594
1574
this._statusSection.addMenuItem(this._statusItem);
1595
1575
this._statusSection.addAction(_("Enable networking"), Lang.bind(this, function() {
1596
1576
this._client.networking_enabled = true;
1697
setIcon: function(iconName) {
1698
this._primaryIcon.icon_name = iconName;
1701
1677
_ensureSource: function() {
1702
1678
if (!this._source) {
1703
1679
this._source = new MessageTray.Source(_("Network Manager"),
1704
'network-transmit-receive',
1705
St.IconType.SYMBOLIC);
1680
'network-transmit-receive');
1707
1682
this._source.connect('destroy', Lang.bind(this, function() {
1708
1683
this._source = null;
1773
1748
this._ensureSource();
1775
1750
let icon = new St.Icon({ icon_name: iconName,
1776
icon_type: St.IconType.SYMBOLIC,
1777
icon_size: this._source.ICON_SIZE
1751
icon_size: MessageTray.NOTIFICATION_ICON_SIZE });
1779
1752
device._notification = new MessageTray.Notification(this._source, title, text,
1780
1753
{ icon: icon });
1781
1754
device._notification.setUrgency(urgency);
1792
1765
wrapper._activationFailedId = wrapper.connect('activation-failed', Lang.bind(this, function(device, reason) {
1793
1766
// XXX: nm-applet has no special text depending on reason
1794
1767
// but I'm not sure of this generic message
1795
this._notifyForDevice(device, 'network-error',
1768
this._notifyForDevice(device, 'network-error-symbolic',
1796
1769
_("Connection failed"),
1797
1770
_("Activation of network connection failed"),
1798
1771
MessageTray.Urgency.HIGH);
1817
1790
let wrapperClass = this._dtypes[device.get_device_type()];
1818
1791
if (wrapperClass) {
1819
1792
let wrapper = this._makeWrapperDevice(wrapperClass, device);
1821
1793
let section = this._devices[wrapper.category].section;
1822
1794
let devices = this._devices[wrapper.category].devices;
1846
1817
this._syncSectionTitle(wrapper.category)
1820
_getSupportedActiveConnections: function() {
1821
let activeConnections = this._client.get_active_connections() || [ ];
1822
let supportedConnections = [];
1824
for (let i = 0; i < activeConnections.length; i++) {
1825
let devices = activeConnections[i].get_devices();
1826
if (!devices || !devices[0])
1828
// Ignore connections via unrecognized device types
1829
if (!this._dtypes[devices[0].device_type])
1832
// Ignore slave connections
1833
let connectionPath = activeConnections[i].connection;
1834
let connection = this._settings.get_connection_by_path(connectionPath)
1835
if (this._ignoreConnection(connection))
1838
supportedConnections.push(activeConnections[i]);
1840
return supportedConnections;
1849
1843
_syncActiveConnections: function() {
1850
1844
let closedConnections = [ ];
1851
let newActiveConnections = this._client.get_active_connections() || [ ];
1845
let newActiveConnections = this._getSupportedActiveConnections();
1852
1846
for (let i = 0; i < this._activeConnections.length; i++) {
1853
1847
let a = this._activeConnections[i];
1854
1848
if (newActiveConnections.indexOf(a) == -1) // connection is removed
1952
1946
this._updateIcon();
1949
_ignoreConnection: function(connection) {
1950
let setting = connection.get_setting_connection();
1954
// Ignore slave connections
1955
if (setting.get_master())
1955
1961
_readConnections: function() {
1956
1962
let connections = this._settings.list_connections();
1957
1963
for (let i = 0; i < connections.length; i++) {
1958
1964
let connection = connections[i];
1965
if (this._ignoreConnection(connection))
1959
1967
if (connection._updatedId) {
1960
1968
// connection was already seen (for example because NetworkManager was restarted)
1971
1979
_newConnection: function(settings, connection) {
1980
if (this._ignoreConnection(connection))
1972
1982
if (connection._updatedId) {
1973
1983
// connection was already seen
2048
2058
_syncNMState: function() {
2049
if (!this._client.manager_running) {
2050
log('NetworkManager is not running, hiding...');
2059
this.mainIcon.visible = this._client.manager_running;
2060
this.actor.visible = this.mainIcon.visible;
2057
2062
if (!this._client.networking_enabled) {
2058
this.setIcon('network-offline');
2063
this.setIcon('network-offline-symbolic');
2059
2064
this._hideDevices();
2060
2065
this._statusItem.label.text = _("Networking is disabled");
2061
2066
this._statusSection.actor.show();
2073
2078
let hasMobileIcon = false;
2076
this.setIcon('network-offline');
2081
this.setIcon('network-offline-symbolic');
2077
2082
} else if (mc.state == NetworkManager.ActiveConnectionState.ACTIVATING) {
2078
2083
switch (mc._section) {
2079
2084
case NMConnectionCategory.WWAN:
2080
this.setIcon('network-cellular-acquiring');
2085
this.setIcon('network-cellular-acquiring-symbolic');
2082
2087
case NMConnectionCategory.WIRELESS:
2083
this.setIcon('network-wireless-acquiring');
2088
this.setIcon('network-wireless-acquiring-symbolic');
2085
2090
case NMConnectionCategory.WIRED:
2086
this.setIcon('network-wired-acquiring');
2091
this.setIcon('network-wired-acquiring-symbolic');
2089
2094
// fallback to a generic connected icon
2090
2095
// (it could be a private connection of some other user)
2091
this.setIcon('network-wired-acquiring');
2096
this.setIcon('network-wired-acquiring-symbolic');
2103
2108
log('An active wireless connection, in infrastructure mode, involves no access point?');
2106
this.setIcon('network-wireless-connected');
2111
this.setIcon('network-wireless-connected-symbolic');
2108
2113
if (this._activeAccessPoint != ap) {
2109
2114
if (this._accessPointUpdateId)
2110
2115
this._activeAccessPoint.disconnect(this._accessPointUpdateId);
2111
2116
this._activeAccessPoint = ap;
2112
2117
this._activeAccessPointUpdateId = ap.connect('notify::strength', Lang.bind(this, function() {
2113
this.setIcon('network-wireless-signal-' + signalToIcon(ap.strength));
2118
this.setIcon('network-wireless-signal-' + signalToIcon(ap.strength) + '-symbolic');
2116
this.setIcon('network-wireless-signal-' + signalToIcon(ap.strength));
2121
this.setIcon('network-wireless-signal-' + signalToIcon(ap.strength) + '-symbolic');
2117
2122
hasApIcon = true;
2141
2146
this._mobileUpdateDevice.disconnect(this._mobileUpdateId);
2142
2147
this._mobileUpdateDevice = dev.mobileDevice;
2143
2148
this._mobileUpdateId = dev.mobileDevice.connect('notify::signal-quality', Lang.bind(this, function() {
2144
this.setIcon('network-cellular-signal-' + signalToIcon(dev.mobileDevice.signal_quality));
2149
this.setIcon('network-cellular-signal-' + signalToIcon(dev.mobileDevice.signal_quality) + '-symbolic');
2147
this.setIcon('network-cellular-signal-' + signalToIcon(dev.mobileDevice.signal_quality));
2152
this.setIcon('network-cellular-signal-' + signalToIcon(dev.mobileDevice.signal_quality) + '-symbolic');
2148
2153
hasMobileIcon = true;
2151
2156
// fallback to a generic connected icon
2152
2157
// (it could be a private connection of some other user)
2153
this.setIcon('network-wired');
2158
this.setIcon('network-wired-symbolic');
2158
2163
// update VPN indicator
2159
2164
if (this._vpnConnection) {
2160
let vpnIconName = 'network-vpn';
2165
let vpnIconName = 'network-vpn-symbolic';
2161
2166
if (this._vpnConnection.state == NetworkManager.ActiveConnectionState.ACTIVATING)
2162
vpnIconName = 'network-vpn-acquiring';
2167
vpnIconName = 'network-vpn-acquiring-symbolic';
2164
2169
// only show a separate icon when we're using a wireless/3g connection
2165
2170
if (mc._section == NMConnectionCategory.WIRELESS ||
2166
2171
mc._section == NMConnectionCategory.WWAN) {
2167
this._secondaryIcon.icon_name = vpnIconName;
2168
this._secondaryIcon.visible = true;
2172
this.secondaryIcon.icon_name = vpnIconName;
2173
this.secondaryIcon.show();
2170
2175
this.setIcon(vpnIconName);
2171
this._secondaryIcon.visible = false;
2176
this.secondaryIcon.hide();
2174
this._secondaryIcon.visible = false;
2179
this.secondaryIcon.hide();
2177
2182
// cleanup stale signal connections