NetworkMenu: keep wirelesss networks in predictable order
Adds a function that compares wireless networks and keeps them sorted at all times. Order is: first already configured connections, then first secure networks, then alphabtic. Also, the appearance of a new access point no longer causes the whole menu to be rebuilt (but it still linear searches for the position, I guess that could be skipped), which caused the addition of more code for tracking the active access point. https://bugzilla.gnome.org/show_bug.cgi?id=646580
This commit is contained in:
parent
9d5906dae3
commit
d0780d1622
@ -42,6 +42,10 @@ const NM80211Mode = NetworkManager['80211Mode'];
|
|||||||
const NM80211ApFlags = NetworkManager['80211ApFlags'];
|
const NM80211ApFlags = NetworkManager['80211ApFlags'];
|
||||||
const NM80211ApSecurityFlags = NetworkManager['80211ApSecurityFlags'];
|
const NM80211ApSecurityFlags = NetworkManager['80211ApSecurityFlags'];
|
||||||
|
|
||||||
|
// number of wireless networks that should be visible
|
||||||
|
// (the remaining are placed into More...)
|
||||||
|
const NUM_VISIBLE_NETWORKS = 5;
|
||||||
|
|
||||||
function macToArray(string) {
|
function macToArray(string) {
|
||||||
return string.split(':').map(function(el) {
|
return string.split(':').map(function(el) {
|
||||||
return parseInt(el, 16);
|
return parseInt(el, 16);
|
||||||
@ -1036,6 +1040,7 @@ NMDeviceWireless.prototype = {
|
|||||||
item: null,
|
item: null,
|
||||||
accessPoints: [ ap ]
|
accessPoints: [ ap ]
|
||||||
};
|
};
|
||||||
|
obj.ssidText = NetworkManager.utils_ssid_to_utf8(obj.ssid);
|
||||||
this._networks.push(obj);
|
this._networks.push(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1048,6 +1053,14 @@ NMDeviceWireless.prototype = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (this.device.active_access_point) {
|
||||||
|
this._activeNetwork = this._networks[this._findNetwork(this.device.active_access_point)];
|
||||||
|
} else {
|
||||||
|
this._activeNetwork = null;
|
||||||
|
}
|
||||||
|
this._networks.sort(this._networkSortFunction);
|
||||||
|
|
||||||
|
this._apChangedId = device.connect('notify::active-access-point', Lang.bind(this, this._activeApChanged));
|
||||||
this._apAddedId = device.connect('access-point-added', Lang.bind(this, this._accessPointAdded));
|
this._apAddedId = device.connect('access-point-added', Lang.bind(this, this._accessPointAdded));
|
||||||
this._apRemovedId = device.connect('access-point-removed', Lang.bind(this, this._accessPointRemoved));
|
this._apRemovedId = device.connect('access-point-removed', Lang.bind(this, this._accessPointRemoved));
|
||||||
|
|
||||||
@ -1055,8 +1068,13 @@ NMDeviceWireless.prototype = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
destroy: function() {
|
destroy: function() {
|
||||||
if (this._apAddedId) {
|
if (this._apChangedId) {
|
||||||
// see above for this HACK
|
// see above for this HACK
|
||||||
|
GObject.Object.prototype.disconnect.call(this.device, this._apChangedId);
|
||||||
|
this._apChangedId = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this._apAddedId) {
|
||||||
GObject.Object.prototype.disconnect.call(this.device, this._apAddedId);
|
GObject.Object.prototype.disconnect.call(this.device, this._apAddedId);
|
||||||
this._apAddedId = 0;
|
this._apAddedId = 0;
|
||||||
}
|
}
|
||||||
@ -1122,6 +1140,19 @@ NMDeviceWireless.prototype = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_activeApChanged: function() {
|
||||||
|
this._activeNetwork = null;
|
||||||
|
|
||||||
|
let activeAp = this.device.active_access_point;
|
||||||
|
|
||||||
|
if (activeAp) {
|
||||||
|
let pos = this._findNetwork(activeAp);
|
||||||
|
this._activeNetwork = this._networks[pos];
|
||||||
|
}
|
||||||
|
|
||||||
|
// we don't refresh the view here, setActiveConnection will
|
||||||
|
},
|
||||||
|
|
||||||
_getApSecurityType: function(accessPoint) {
|
_getApSecurityType: function(accessPoint) {
|
||||||
if (accessPoint._secType)
|
if (accessPoint._secType)
|
||||||
return accessPoint._secType;
|
return accessPoint._secType;
|
||||||
@ -1151,6 +1182,32 @@ NMDeviceWireless.prototype = {
|
|||||||
return type;
|
return type;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_networkSortFunction: function(one, two) {
|
||||||
|
let oneHasConnection = one.connections.length != 0;
|
||||||
|
let twoHasConnection = two.connections.length != 0;
|
||||||
|
|
||||||
|
// place known connections first
|
||||||
|
// (-1 = good order, 1 = wrong order)
|
||||||
|
if (oneHasConnection && !twoHasConnection)
|
||||||
|
return -1;
|
||||||
|
else if (!oneHasConnection && twoHasConnection)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
let oneHasSecurity = one.security != NMAccessPointSecurity.NONE;
|
||||||
|
let twoHasSecurity = two.security != NMAccessPointSecurity.NONE;
|
||||||
|
|
||||||
|
// place secure connections first
|
||||||
|
// (we treat WEP/WPA/WPA2 the same as there is no way to
|
||||||
|
// take them apart from the UI)
|
||||||
|
if (oneHasSecurity && !twoHasSecurity)
|
||||||
|
return -1;
|
||||||
|
else if (!oneHasSecurity && twoHasSecurity)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
// sort alphabetically
|
||||||
|
return GLib.utf8_collate(one.ssidText, two.ssidText);
|
||||||
|
},
|
||||||
|
|
||||||
_networkCompare: function(network, accessPoint) {
|
_networkCompare: function(network, accessPoint) {
|
||||||
if (!ssidCompare(network.ssid, accessPoint.get_ssid()))
|
if (!ssidCompare(network.ssid, accessPoint.get_ssid()))
|
||||||
return false;
|
return false;
|
||||||
@ -1173,6 +1230,8 @@ NMDeviceWireless.prototype = {
|
|||||||
_accessPointAdded: function(device, accessPoint) {
|
_accessPointAdded: function(device, accessPoint) {
|
||||||
let pos = this._findNetwork(accessPoint);
|
let pos = this._findNetwork(accessPoint);
|
||||||
let apObj;
|
let apObj;
|
||||||
|
let needsupdate = false;
|
||||||
|
|
||||||
if (pos != -1) {
|
if (pos != -1) {
|
||||||
apObj = this._networks[pos];
|
apObj = this._networks[pos];
|
||||||
if (apObj.accessPoints.indexOf(accessPoint) != -1) {
|
if (apObj.accessPoints.indexOf(accessPoint) != -1) {
|
||||||
@ -1181,6 +1240,8 @@ NMDeviceWireless.prototype = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
apObj.accessPoints.push(accessPoint);
|
apObj.accessPoints.push(accessPoint);
|
||||||
|
if (apObj.item)
|
||||||
|
apObj.item.updateAccessPoints(apObj.accessPoints);
|
||||||
} else {
|
} else {
|
||||||
apObj = { ssid: accessPoint.get_ssid(),
|
apObj = { ssid: accessPoint.get_ssid(),
|
||||||
mode: accessPoint.mode,
|
mode: accessPoint.mode,
|
||||||
@ -1189,7 +1250,8 @@ NMDeviceWireless.prototype = {
|
|||||||
item: null,
|
item: null,
|
||||||
accessPoints: [ accessPoint ]
|
accessPoints: [ accessPoint ]
|
||||||
};
|
};
|
||||||
this._networks.push(apObj);
|
apObj.ssidText = NetworkManager.utils_ssid_to_utf8(apObj.ssid);
|
||||||
|
needsupdate = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if this enables new connections for this group
|
// check if this enables new connections for this group
|
||||||
@ -1198,12 +1260,44 @@ NMDeviceWireless.prototype = {
|
|||||||
if (this._connectionValidForAP(connection, accessPoint) &&
|
if (this._connectionValidForAP(connection, accessPoint) &&
|
||||||
apObj.connections.indexOf(connection) == -1) {
|
apObj.connections.indexOf(connection) == -1) {
|
||||||
apObj.connections.push(connection);
|
apObj.connections.push(connection);
|
||||||
|
|
||||||
|
// this potentially changes the order
|
||||||
|
needsupdate = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// update everything
|
if (needsupdate) {
|
||||||
|
if (apObj.item)
|
||||||
|
apObj.item.destroy();
|
||||||
|
|
||||||
|
if (pos != -1)
|
||||||
|
this._networks.splice(pos, 1);
|
||||||
|
|
||||||
|
if (this._networks.length == 0) {
|
||||||
|
// only network in the list
|
||||||
|
this._networks.push(apObj);
|
||||||
this._clearSection();
|
this._clearSection();
|
||||||
this._createSection();
|
this._createSection();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// skip networks that should appear earlier
|
||||||
|
let menuPos = 0;
|
||||||
|
for (pos = 0;
|
||||||
|
pos < this._networks.length &&
|
||||||
|
this._networkSortFunction(this._networks[i], apObj) < 0; ++pos) {
|
||||||
|
if (this._networks[pos] != this._activeNetwork)
|
||||||
|
menuPos++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// (re-)add the network
|
||||||
|
this._networks.splice(pos, 0, apObj);
|
||||||
|
|
||||||
|
if (this._shouldShowConnectionList()) {
|
||||||
|
menuPos += (this._activeConnectionItem ? 1 : 0);
|
||||||
|
this._createNetworkItem(apObj, menuPos);
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_accessPointRemoved: function(device, accessPoint) {
|
_accessPointRemoved: function(device, accessPoint) {
|
||||||
@ -1315,6 +1409,12 @@ NMDeviceWireless.prototype = {
|
|||||||
// remove the connection from the access point group
|
// remove the connection from the access point group
|
||||||
connections.splice(k);
|
connections.splice(k);
|
||||||
anyauto = connections.length == 0;
|
anyauto = connections.length == 0;
|
||||||
|
|
||||||
|
if (anyauto) {
|
||||||
|
// this potentially changes the sorting order
|
||||||
|
forceupdate = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
if (apObj.item) {
|
if (apObj.item) {
|
||||||
if (apObj.item instanceof PopupMenu.PopupSubMenuMenuItem) {
|
if (apObj.item instanceof PopupMenu.PopupSubMenuMenuItem) {
|
||||||
let items = apObj.item.menu.getMenuItems();
|
let items = apObj.item.menu.getMenuItems();
|
||||||
@ -1340,6 +1440,7 @@ NMDeviceWireless.prototype = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (forceupdate || anyauto) {
|
if (forceupdate || anyauto) {
|
||||||
|
this._networks.sort(this._networkSortFunction);
|
||||||
this._clearSection();
|
this._clearSection();
|
||||||
this._createSection();
|
this._createSection();
|
||||||
}
|
}
|
||||||
@ -1355,42 +1456,24 @@ NMDeviceWireless.prototype = {
|
|||||||
this._connections.push(obj);
|
this._connections.push(obj);
|
||||||
|
|
||||||
// find an appropriate access point
|
// find an appropriate access point
|
||||||
let any = false, forceupdate = false;
|
let forceupdate = false;
|
||||||
for (let i = 0; i < this._networks.length; i++) {
|
for (let i = 0; i < this._networks.length; i++) {
|
||||||
let apObj = this._networks[i];
|
let apObj = this._networks[i];
|
||||||
|
|
||||||
// Check if connection is valid for any of these access points
|
// Check if connection is valid for any of these access points
|
||||||
let any = false;
|
|
||||||
for (let k = 0; k < apObj.accessPoints.length; k++) {
|
for (let k = 0; k < apObj.accessPoints.length; k++) {
|
||||||
let ap = apObj.accessPoints[k];
|
let ap = apObj.accessPoints[k];
|
||||||
if (this._connectionValidForAP(connection, ap)) {
|
if (this._connectionValidForAP(connection, ap)) {
|
||||||
apObj.connections.push(connection);
|
apObj.connections.push(connection);
|
||||||
any = true;
|
// this potentially changes the sorting order
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (any && this._shouldShowConnectionList()) {
|
|
||||||
// we need to show this connection
|
|
||||||
if (apObj.item && apObj.item.menu) {
|
|
||||||
// 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);
|
|
||||||
this.section.addMenuItem(apObj.item);
|
|
||||||
} else {
|
|
||||||
apObj.item = null;
|
|
||||||
// we need to force an update to create the submenu
|
|
||||||
forceupdate = true;
|
forceupdate = true;
|
||||||
}
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (forceupdate) {
|
if (forceupdate) {
|
||||||
|
this._networks.sort(this._networkSortFunction);
|
||||||
this._clearSection();
|
this._clearSection();
|
||||||
this._createSection();
|
this._createSection();
|
||||||
}
|
}
|
||||||
@ -1473,32 +1556,12 @@ NMDeviceWireless.prototype = {
|
|||||||
return connection;
|
return connection;
|
||||||
},
|
},
|
||||||
|
|
||||||
_createSection: function() {
|
_createNetworkItem: function(apObj, position) {
|
||||||
if (!this._shouldShowConnectionList())
|
|
||||||
return;
|
|
||||||
|
|
||||||
if(this._activeConnection) {
|
|
||||||
this._createActiveConnectionItem();
|
|
||||||
this.section.addMenuItem(this._activeConnectionItem);
|
|
||||||
}
|
|
||||||
|
|
||||||
let activeAp = this.device.active_access_point;
|
|
||||||
let activeApSsid = activeAp ? activeAp.get_ssid() : null;
|
|
||||||
|
|
||||||
// we want five access points in the menu, including the active one
|
|
||||||
let numItems = this._activeConnection ? 4 : 5;
|
|
||||||
|
|
||||||
for(let j = 0; j < this._networks.length; j++) {
|
|
||||||
let apObj = this._networks[j];
|
|
||||||
if(activeAp && ssidCompare(apObj.ssid, activeApSsid))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
let menuItem;
|
|
||||||
if(apObj.connections.length > 0) {
|
if(apObj.connections.length > 0) {
|
||||||
if (apObj.connections.length == 1)
|
if (apObj.connections.length == 1)
|
||||||
apObj.item = this._createAPItem(apObj.connections[0], apObj, false);
|
apObj.item = this._createAPItem(apObj.connections[0], apObj, false);
|
||||||
else {
|
else {
|
||||||
let title = NetworkManager.utils_ssid_to_utf8(apObj.ssid) || _("<unknown>");
|
let title = apObj.ssidText;
|
||||||
apObj.item = new PopupMenu.PopupSubMenuMenuItem(title);
|
apObj.item = new PopupMenu.PopupSubMenuMenuItem(title);
|
||||||
apObj.item._apObj = apObj;
|
apObj.item._apObj = apObj;
|
||||||
for (let i = 0; i < apObj.connections.length; i++)
|
for (let i = 0; i < apObj.connections.length; i++)
|
||||||
@ -1513,16 +1576,34 @@ NMDeviceWireless.prototype = {
|
|||||||
this._client.add_and_activate_connection(connection, this.device, accessPoints[0].dbus_path, null)
|
this._client.add_and_activate_connection(connection, this.device, accessPoints[0].dbus_path, null)
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
if (position < NUM_VISIBLE_NETWORKS)
|
||||||
if (j < numItems)
|
|
||||||
this.section.addMenuItem(apObj.item);
|
this.section.addMenuItem(apObj.item);
|
||||||
else {
|
else {
|
||||||
if (!this._overflowItem) {
|
if (!this._overflowItem) {
|
||||||
this._overflowItem = new PopupMenu.PopupSubMenuMenuItem(_("More..."));
|
this._overflowItem = new PopupMenu.PopupSubMenuMenuItem(_("More..."));
|
||||||
this.section.addMenuItem(this._overflowItem);
|
this.section.addMenuItem(this._overflowItem);
|
||||||
}
|
}
|
||||||
this._overflowItem.menu.addMenuItem(apObj.item);
|
this._overflowItem.menu.addMenuItem(apObj.item, position - NUM_VISIBLE_NETWORKS);
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_createSection: function() {
|
||||||
|
if (!this._shouldShowConnectionList())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(this._activeConnection) {
|
||||||
|
this._createActiveConnectionItem();
|
||||||
|
this.section.addMenuItem(this._activeConnectionItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
let activeOffset = this._activeConnectionItem ? 1 : 0;
|
||||||
|
|
||||||
|
for(let j = 0; j < this._networks.length; j++) {
|
||||||
|
let apObj = this._networks[j];
|
||||||
|
if (apObj == this._activeNetwork)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
this._createNetworkItem(apObj, j + activeOffset);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user