The unified diff between revisions [05448376..] and [aea25ad8..] is displayed below. It can also be downloaded as a raw diff.

#
#
# patch "debian/control"
#  from [effac33cf35748260669d0156d71229d2f6c9baa]
#    to [4cf2ceb21877b0647eac61b1f3d270b8d797325f]
#
# patch "interapplet.py"
#  from [9544599caa57f2b5853b7faa0b4b69feff12e0c6]
#    to [c3907cff0e9d8395fae3790af1820d9cb9f2aca8]
#
============================================================
--- debian/control	effac33cf35748260669d0156d71229d2f6c9baa
+++ debian/control	4cf2ceb21877b0647eac61b1f3d270b8d797325f
@@ -8,6 +8,7 @@ Depends: python-gtk2 (>= 2.6.0), python2
 Package: interapplet
 Architecture: all
 Depends: python-gtk2 (>= 2.6.0), python2.4-gamin (>= 0.0.26),
-  python-gnome2 (>= 2.10.0), python-gnome2-extras (>= 2.10.0), gksu
+  python-gnome2 (>= 2.10.0), python-gnome2-extras (>= 2.10.0),
+  python2.4-dbus (>= 0.23), gksu
 Description: Interface configuration applet for GNOME
   Written in Python and providing a GNOME panel applet.
============================================================
--- interapplet.py	9544599caa57f2b5853b7faa0b4b69feff12e0c6
+++ interapplet.py	c3907cff0e9d8395fae3790af1820d9cb9f2aca8
@@ -27,6 +27,7 @@ import gamin
 import gnomeapplet
 import gobject
 import gamin
+import dbus

 import popen2
 import fcntl
@@ -58,21 +59,12 @@ class InterfaceInfo:
 		self.mappings = set()
 		self.mappable = set()

-		# FIXME this will never update, which is awful
-		exclude = set(('gre0', 'lo', 'tunl0', 'dummy0'))
-		for line in open('/proc/net/dev'):
-			m = re.match(r' *([^:]+):', line)
-			if m:
-				ifname = m.groups()[0].strip()
-				if ifname not in exclude: self.mappable.add(ifname)
-
-		fd = open(file)
-
 		mapping = re.compile(r'^\s?mapping\s+([\w_:]+)')
 		map = re.compile(r'^\s?map\s+([\w_]+)\s+([\w_]+)')
 		auto = re.compile(r'^\s?auto[\s^]')
 		iface = re.compile(r'^\s?iface\s+([\w_]+)\s+([\w_]+)\s+([\w_]+)')

+		fd = open(file)
 		for line in fd:
 			m = mapping.match(line)
 			if m:
@@ -94,6 +86,53 @@ class InterfaceState:
 			m = mapping.match(line)
 			if m: self.state[m.groups()[0]] = m.groups()[1]

+class DeviceInfo:
+	def __init__(self, change_cb):
+		self.change_cb = change_cb
+		self.udi_to_device = {}
+
+		self.bus = dbus.Bus(dbus.Bus.TYPE_SYSTEM)
+		self.hal_service = self.bus.get_service("org.freedesktop.Hal")
+		self.hal_manager = self.hal_service.get_object("/org/freedesktop/Hal/Manager",
+							       "org.freedesktop.Hal.Manager")
+		network_devices = self.hal_manager.FindDeviceByCapability('net')
+		for device_udi in network_devices:
+			self.add_by_udi(device_udi)
+		self.bus.add_signal_receiver(self.device_change_cb,
+					     "DeviceAdded",
+					     "org.freedesktop.Hal.Manager",
+					     "org.freedesktop.Hal",
+					     "/org/freedesktop/Hal/Manager")
+		self.bus.add_signal_receiver(self.device_change_cb,
+					     "DeviceRemoved",
+					     "org.freedesktop.Hal.Manager",
+					     "org.freedesktop.Hal",
+					     "/org/freedesktop/Hal/Manager")
+	def add_by_udi(self, udi):
+		if not self.udi_to_device.has_key(udi):
+			device = self.hal_service.get_object(udi, "org.freedesktop.Hal.Device")
+			category = device.GetProperty('info.category')
+			if not category.startswith('net.'): return
+			product = device.GetProperty('info.product')
+			interface = device.GetProperty('net.interface')
+			self.udi_to_device[udi] = ("%s: %s" % (interface, product), interface)
+	def remove_by_udi(self, udi):
+		if self.udi_to_device.has_key(udi):
+			self.udi_to_device.pop(udi)
+	def get_devices(self):
+		return self.udi_to_device.values()
+	def device_change_cb(self, dbus_if, dbus_member, dbus_svc, dbus_obj_path, dbus_message):
+		if dbus_member == "DeviceAdded":
+			[device_udi] = dbus_message.get_args_list()
+			print "DeviceAdded", device_udi
+			self.add_by_udi(device_udi)
+			self.change_cb()
+		elif dbus_member == "DeviceRemoved":
+			[device_udi] = dbus_message.get_args_list()
+			print "DeviceRemoved", device_udi
+			self.remove_by_udi(device_udi)
+			self.change_cb()
+
 class InterfaceApplet(gnomeapplet.Applet):
 	def __init__(self, applet, iid):
 		self.run_queue = []
@@ -114,7 +153,7 @@ class InterfaceApplet(gnomeapplet.Applet

                 self.log_window = gtk.Window()
 		self.log_window.resize(600,150)
-                self.log_window.set_title("Interface Applet Log")
+                self.log_window.set_title("InterApplet Log")
                 self.scrolled_window = gtk.ScrolledWindow()
 		self.scrolled_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
                 self.text_view = gtk.TextView()
@@ -132,11 +171,8 @@ class InterfaceApplet(gnomeapplet.Applet
 		# load interface state and update it using gamin
 		self.if_info = InterfaceInfo(interfaces_file)
 		self.if_state = InterfaceState(ifstate_file)
+		self.device_info = DeviceInfo(self.devices_changed_cb)
 		self.menu = self.build_menu()
-		# disabled by [GMB]
-		# causes irrating prompt when first starting program, and is probably
-		# not needed.
-		#self.init_state_files()
 		self.mon = gamin.WatchMonitor()
 		self.mon.watch_file(ifstate_file, self.interfaces_changed_cb)
 		self.mon.watch_file(interfaces_file, self.interfaces_changed_cb)
@@ -241,13 +277,11 @@ class InterfaceApplet(gnomeapplet.Applet
 		command = '/sbin/ifup ' + pipes.quote(int)
 		if mapping != None: command += "=" + pipes.quote(mapping)
 		self.run_command("/usr/bin/gksudo %s" % (pipes.quote(command)))
-	def init_state_files(self):
-		for mapping in self.if_state.state:
-			if not mapping in self.if_info.mappings: continue
-			self.update_state(mapping, self.if_state.state[mapping])
 	def mon_cb(self, source, condition, user_data=None):
 		self.mon.handle_events()
 		return True
+	def devices_changed_cb(self):
+		self.menu = self.build_menu()
 	def interfaces_changed_cb(self, path, event):
 		# we only care about the file getting created, or the file
 		# being modified
@@ -336,17 +370,17 @@ class InterfaceApplet(gnomeapplet.Applet
 		return menu
 	def build_menu(self):
 		menu = gtk.Menu()
-		mappings = list(self.if_info.mappable)
-		mappings.sort()
+		mappings = list(self.device_info.get_devices())
+		mappings.sort(lambda x, y: cmp(x[0], y[0]))
 		nin = gtk.Image()
 		if len(mappings) == 0:
 			item = gtk.ImageMenuItem("No mapable interfaces found.")
 			item.set_sensitive(False)
 			item.show()
 			menu.append(item)
-		for mapping in mappings:
+		for description, mapping in mappings:
 			self.build_mapping_menu(mapping)
-			item = gtk.ImageMenuItem(mapping)
+			item = gtk.ImageMenuItem(description)
 			item.set_submenu(self.build_mapping_menu(mapping))
 			item.show()
 			menu.append(item)