From c5863cf56f863771b385a949bcea12936228bcf0 Mon Sep 17 00:00:00 2001 From: imdano <> Date: Mon, 10 Dec 2007 16:48:37 +0000 Subject: [PATCH] Moved autoreconnect code and connection status updates into the daemon. Daemon now sends D-Bus signals when status changes, which the tray listens for and updates icon/tooltip when received. --- daemon.py | 170 ++++++++++++++++++++++++++++++++- gui.py | 2 +- wicd.py | 275 +++++++++++++++--------------------------------------- 3 files changed, 242 insertions(+), 205 deletions(-) diff --git a/daemon.py b/daemon.py index 0ea26e9..ce13ea7 100644 --- a/daemon.py +++ b/daemon.py @@ -8,6 +8,7 @@ components should be run as a normal user. class LogWriter() -- Class to redirect stdout and stderr to a log file. class ConnectionWizard() -- DBUS interface to manage the network. +class ConnectionStatus() -- Updates the current connection state def usage() -- Print usage information. def daemonize() -- Daemonize the current process with a double fork. def main() -- The wicd daemon main loop. @@ -401,6 +402,11 @@ class ConnectionWizard(dbus.service.Object): print 'calling wired profile chooser' daemon.SetNeedWiredProfileChooser(True) + @dbus.service.signal(dbus_interface='org.wicd.daemon', signature='') + def StatusChanged(self): + """ Called when the current connection status has changed """ + pass + ########## WIRELESS FUNCTIONS ################################# @@ -453,7 +459,6 @@ class ConnectionWizard(dbus.service.Object): # Break once the network is found break self.LastScan = master_scan - #end function FreshScan @dbus.service.method('org.wicd.daemon.wireless') def DisconnectWireless(self): @@ -549,6 +554,21 @@ class ConnectionWizard(dbus.service.Object): return str(iface) #end function DetectWirelessInterface + @dbus.service.method('org.wicd.daemon.wireless') + def GetPrintableSignalStrength(self): + """ Assigns a signal strength appropriate for display + + This is used separately from the raw signal strength retrieving + functions as a way to simply the strength polling process for + the GUI and tray icon, by returning the strength that the user + has requested to be displayed in wicd preferences. + """ + + if self.GetSignalDisplayType() == 0: + return self.GetCurrentSignalStrength() + else: + return GetCurrentDBMStrength() + @dbus.service.method('org.wicd.daemon.wireless') def GetCurrentSignalStrength(self): ''' Returns the current signal strength ''' @@ -572,7 +592,6 @@ class ConnectionWizard(dbus.service.Object): def GetCurrentNetwork(self): ''' Returns the current network ''' current_network = str(self.wifi.GetCurrentNetwork()) - print current_network return current_network #end function GetCurrentNetwork @@ -630,7 +649,8 @@ class ConnectionWizard(dbus.service.Object): print 'wireless connecting',status return status else: - print 'wireless connecting',False + if self.debug_mode == 1: + print 'wireless connecting',False return False #end function CheckIfWirelessConnecting @@ -1311,11 +1331,155 @@ def main(argv): session_bus = dbus.SystemBus() bus_name = dbus.service.BusName('org.wicd.daemon', bus=session_bus) object = ConnectionWizard(bus_name, auto_connect=auto_scan) + connection_status = ConnectionStatus(object) + + gobject.timeout_add(3000, connection_status.update_connection_status) # Enter the main loop mainloop = gobject.MainLoop() mainloop.run() +class ConnectionStatus(): + def __init__(self, connection): + """Initialize variables needed for the connection status methods.""" + self.last_strength = -2 + self.still_wired = False + self.network = '' + self.tried_reconnect = False + self.connection_lost_counter = 0 + self.conn = connection + self.status_changed = False + + def check_for_wired_connection(self, wired_ip): + """Checks for an active wired connection + + Checks for and updates the tray icon for an active wired connection + Returns True if wired connection is active, false if inactive. + + """ + conn = self.conn + if wired_ip is not None and conn.CheckPluggedIn(): + # Only change the interface if it's not already set for wired + if not self.still_wired: + conn.SetCurrentInterface(conn.GetWiredInterface()) + self.still_wired = True + self.status_changed = True + return True + # Wired connection isn't active + self.still_wired = False + return False + + def check_for_wireless_connection(self, wireless_ip): + """Checks for an active wireless connection + + Checks for and updates the tray icon for an active + wireless connection. Returns True if wireless connection + is active, and False otherwise. + + """ + conn = self.conn + + # Make sure we have an IP before we do anything else. + if conn.GetWirelessIP() is None: + return False + + # Reset this, just in case. + self.tried_reconnect = False + + # Try getting signal strength, and default to 0 + # if something goes wrong. + try: + if conn.GetSignalDisplayType() == 0: + wifi_signal = int(conn.GetCurrentSignalStrength()) + else: + wifi_signal = int(conn.GetCurrentDBMStrength()) + except: + wifi_signal = 0 + + if wifi_signal == 0: + # If we have no signal, increment connection loss counter. + # If we haven't gotten any signal 4 runs in a row (12 seconds), + # try to reconnect. + self.connection_lost_counter += 1 + print self.connection_lost_counter + if self.connection_lost_counter >= 4: + self.connection_lost_counter = 0 + self.auto_reconnect() + return False + else: # If we have a signal, reset the counter + self.connection_lost_counter = 0 + + # Only update if the signal strength has changed because doing I/O + # calls is expensive, and the icon flickers. + if (wifi_signal != self.last_strength or + self.network != conn.GetCurrentNetwork()): + self.last_strength = wifi_signal + self.status_changed = True + conn.SetCurrentInterface(conn.GetWirelessInterface()) + + return True + + def update_connection_status(self): + """Updates the tray icon and current connection status + + Determines the current connection state and sends a dbus signal + announcing when the status changes. Also starts the automatic + reconnection process if necessary. + + """ + conn = self.conn + + wired_ip = conn.GetWiredIP() + wired_found = self.check_for_wired_connection(wired_ip) + if not wired_found: + wifi_ip = conn.GetWirelessIP() + wireless_found = self.check_for_wireless_connection(wifi_ip) + if not wireless_found: # No connection at all + if not conn.CheckIfConnecting(): + self.auto_reconnect() + # Send a D-Bus signal announcing status has changed if necessary. + if self.status_changed: + conn.StatusChanged() + self.status_changed = False + return True + + def auto_reconnect(self): + """Automatically reconnects to a network if needed + + If automatic reconnection is turned on, this method will + attempt to first reconnect to the last used wireless network, and + should that fail will simply run AutoConnect() + + """ + conn = self.conn + conn.SetCurrentInterface('') + self.status_changed = True + + if conn.GetAutoReconnect() and \ + not conn.CheckIfConnecting() and \ + not conn.GetForcedDisconnect(): + print 'Starting automatic reconnect process' + # First try connecting through ethernet + if conn.CheckPluggedIn(): + print "Wired connection available, trying to connect..." + conn.AutoConnect(False) + return + + # Next try the last wireless network we were connected to + cur_net_id = conn.GetCurrentNetworkID() + if cur_net_id > -1: # Needs to be a valid network + if not self.tried_reconnect: + print 'Trying to reconnect to last used wireless \ + network' + conn.ConnectWireless(cur_net_id) + self.tried_reconnect = True + elif conn.CheckIfWirelessConnecting() == False: + print "Couldn't reconnect to last used network, \ + scanning for an autoconnect network..." + conn.AutoConnect(True) + else: + conn.AutoConnect(True) + if __name__ == '__main__': main(sys.argv) diff --git a/gui.py b/gui.py index 43d750f..2c2d0f3 100644 --- a/gui.py +++ b/gui.py @@ -43,7 +43,7 @@ if getattr(dbus, 'version', (0,0,0)) >= (0,41,0): #in any class bus = dbus.SystemBus() try: - print 'attempting to connect daemon...' + print 'Attempting to connect daemon to gui...' proxy_obj = bus.get_object('org.wicd.daemon', '/org/wicd/daemon') print 'success' except: diff --git a/wicd.py b/wicd.py index 49722da..c2dab87 100755 --- a/wicd.py +++ b/wicd.py @@ -78,12 +78,13 @@ bus = dbus.SystemBus() # Connect to the daemon try: - log.write('Attempting to connect daemon...') + print 'Attempting to connect tray to daemon...' proxy_obj = bus.get_object('org.wicd.daemon', '/org/wicd/daemon') - log.write('Success.') + print 'Success.' except: - log.write('Daemon not running...') + print 'Daemon not running...' misc.PromptToStartDaemon() + sys.exit(1) daemon = dbus.Interface(proxy_obj, 'org.wicd.daemon') wireless = dbus.Interface(proxy_obj, 'org.wicd.daemon.wireless') @@ -107,9 +108,9 @@ class TrayIcon(): class TrayConnectionInfo(): - ''' class for updating the tray icon status ''' + """Class for updating the tray icon status""" def __init__(self, tr): - ''' initialize variables needed for the icon status methods ''' + """Initialize variables needed for the icon status methods.""" self.last_strength = -2 self.still_wired = False self.network = '' @@ -118,196 +119,80 @@ class TrayIcon(): self.tr = tr def wired_profile_chooser(self): - ''' Launched the wired profile chooser ''' + """Launch the wired profile chooser.""" daemon.SetNeedWiredProfileChooser(False) chooser = gui.WiredProfileChooser() - def check_for_wired_connection(self, wired_ip): - ''' Checks for an active wired connection + def update_tray_icon(self): + """Updates the tray icon and current connection status""" - Checks for and updates the tray icon for an active wired connection - Returns True if wired connection is active, false if inactive. - - ''' - if wired_ip is not None and wired.CheckPluggedIn(): - # Only set image/tooltip if it hasn't been set already - # and the wire is actually plugged in. - if not self.still_wired: - daemon.SetCurrentInterface(daemon.GetWiredInterface()) - self.tr.set_from_file("images/wired.png") - self.tr.set_tooltip(language['connected_to_wired'].replace('$A', - wired_ip)) - self.still_wired = True + # If we're currently connecting, we can shortcut all other checks + if daemon.CheckIfConnecting(): + self.tr.set_tooltip(language['connecting']) + self.tr.set_from_file(wpath.images + "no-signal.png") return True - return False - - - def check_for_wireless_connection(self, wireless_ip): - ''' Checks for an active wireless connection - - Checks for and updates the tray icon for an active - wireless connection. Returns True if wireless connection - is active, and False otherwise. - - ''' - if wireless.GetWirelessIP() is None: - return False - # Reset this, just in case - self.tried_reconnect = False + cur_iface = daemon.GetCurrentInterface() + wifi_iface = daemon.GetWirelessInterface() + wire_iface = daemon.GetWiredInterface() - # Try getting signal strength, and default to 0 - # if something goes wrong. - try: - if daemon.GetSignalDisplayType() == 0: - wifi_signal = int(wireless.GetCurrentSignalStrength()) - else: - wifi_signal = int(wireless.GetCurrentDBMStrength()) - except: - wifi_signal = 0 - - if wifi_signal == 0: - # If we have no signal, increment connection loss counter. - # If we haven't gotten any signal 4 runs in a row (12 seconds), - # try to reconnect. - self.connection_lost_counter += 1 - print self.connection_lost_counter - if self.connection_lost_counter > 4: - self.connection_lost_counter = 0 - self.auto_reconnect() - return False - - # Only update if the signal strength has changed because doing I/O - # calls is expensive, and the icon flickers - if (wifi_signal != self.last_strength or - self.network != wireless.GetCurrentNetwork()): - self.last_strength = wifi_signal - # Set the string to '' so that when it is put in - # "high-signal" + lock + ".png", there will be nothing - lock = '' - - # cur_net_id needs to be checked because a negative value - # will break the tray when passed to GetWirelessProperty. + # Check for a wired connection + if cur_iface == wire_iface: + wired_ip = wired.GetWiredIP() + self.tr.set_from_file(wpath.images + "wired.png") + self.tr.set_tooltip(language['connected_to_wired'].replace('$A', + wired_ip)) + + # Check for a wireless connection + elif cur_iface == wifi_iface: cur_net_id = wireless.GetCurrentNetworkID() - - if cur_net_id > -1 and \ - wireless.GetWirelessProperty(cur_net_id, "encryption"): - # Set the string to '-lock' so that it will display the - # lock picture - lock = '-lock' - # Update the tooltip and icon picture + if wireless.GetWirelessProperty(cur_net_id, "encryption"): + lock = "-lock" + strength = wireless.GetPrintableSignalStrength() self.network = str(wireless.GetCurrentNetwork()) - daemon.SetCurrentInterface(daemon.GetWirelessInterface()) - str_signal = daemon.FormatSignalForPrinting(str(wifi_signal)) + sig_string = daemon.FormatSignalForPrinting(str(strength)) + wireless_ip = wireless.GetWirelessIP() self.tr.set_tooltip(language['connected_to_wireless'] .replace('$A', self.network) - .replace('$B', str_signal) + .replace('$B', sig_string) .replace('$C', str(wireless_ip))) - self.set_signal_image(wifi_signal, lock) - return True - - - def update_tray_icon(self): - ''' Updates the tray icon and current connection status ''' - - # First check for an active wired network, then for an - # active wireless network. If neither is found, change - # icon to reflect that and run auto_reconnect() - wired_ip = wired.GetWiredIP() - wired_found = self.check_for_wired_connection(wired_ip) - if not wired_found: - self.still_wired = False # We're not wired any more - wifi_ip = wireless.GetWirelessIP() - wireless_found = self.check_for_wireless_connection(wifi_ip) - if not wireless_found: # No connection at all - self.tr.set_from_file("images/no-signal.png") - if daemon.CheckIfConnecting(): - self.tr.set_tooltip(language['connecting']) - self.tr.set_from_file(wpath.images + "no-signal.png") - else: - self.tr.set_tooltip(language['not_connected']) - daemon.SetCurrentInterface('') - self.auto_reconnect() - - if not daemon.GetDebugMode(): - config.EnableLogging() + self.set_signal_image(strength, lock) + + # If we made it here, we don't have a connection + else: + self.tr.set_from_file(wpath.images + "no-signal.png") + self.tr.set_tooltip(language['not_connected']) return True - def set_signal_image(self, wireless_signal, lock): - ''' Sets the tray icon image for an active wireless connection ''' - if wireless_signal == 0: - # We handle a signal of 0 the same regardless of dBm or % - # signal strength. Set the image based on connection loss - # counter, and then return so the counter isn't reset. - if self.connection_lost_counter < 4: - img_file = (wpath.images + "bad-signal" + lock + ".png") - else: - img_file = (wpath.images + "no-signal.png") - self.tr.set_from_file(img_file) - return - elif daemon.GetSignalDisplayType() == 0: + """Sets the tray icon image for an active wireless connection""" + if daemon.GetSignalDisplayType() == 0: if wireless_signal > 75: - img_file = (wpath.images + "high-signal" + lock + ".png") + signal_img = "high-signal" elif wireless_signal > 50: - img_file = (wpath.images + "good-signal" + lock + ".png") + signal_img = "good-signal" elif wireless_signal > 25: - img_file = (wpath.images + "low-signal" + lock + ".png") - elif wireless_signal > 0: - img_file = (wpath.images + "bad-signal" + lock + ".png") + signal_img = "low-signal" + else: + signal_img = "bad-signal" else: if wireless_signal >= -60: - img_file = (wpath.images + "high-signal" + lock + ".png") + signal_img = "high-signal" elif wireless_signal >= -70: - img_file = (wpath.images + "good-signal" + lock + ".png") + signal_img = "good-signal" elif wireless_signal >= -80: - img_file = (wpath.images + "low-signal" + lock + ".png") + signal_img = "low-signal" else: - img_file = (wpath.images + "bad-signal" + lock + ".png") - # Since we have a signal, we should reset - # the connection loss counter. + signal_img = "bad-signal" + + img_file = (wpath.images + signal_img + lock + ".png") self.tr.set_from_file(img_file) - self.connection_lost_counter = 0 - - - def auto_reconnect(self): - ''' Automatically reconnects to a network if needed - - If automatic reconnection is turned on, this method will - attempt to first reconnect to the last used wireless network, and - should that fail will simply run AutoConnect() - - ''' - if wireless.GetAutoReconnect() and \ - not daemon.CheckIfConnecting() and \ - not wireless.GetForcedDisconnect(): - print 'Starting automatic reconnect process' - # First try connecting through ethernet - if wired.CheckPluggedIn(): - print "Wired connection available, trying to connect..." - daemon.AutoConnect(False) - return - - # Next try the last wireless network we were connected to - cur_net_id = wireless.GetCurrentNetworkID() - if cur_net_id > -1: # Needs to be a valid network - if not self.tried_reconnect: - print 'Trying to reconnect to last used wireless \ - network' - wireless.ConnectWireless(cur_net_id) - self.tried_reconnect = True - elif wireless.CheckIfWirelessConnecting() == False: - print "Couldn't reconnect to last used network, \ - scanning for an autoconnect network..." - daemon.AutoConnect(True) - else: - daemon.AutoConnect(True) class TrayIconGUI(): def __init__(self): - menu = ''' + menu = """ @@ -318,7 +203,7 @@ class TrayIcon(): - ''' + """ actions = [ ('Menu', None, 'Menu'), ('Connect', gtk.STOCK_CONNECT, '_Connect...', None, @@ -336,24 +221,20 @@ class TrayIcon(): self.menu = self.manager.get_widget('/Menubar/Menu/About').props.parent self.gui_win = None - def on_activate(self, data=None): - ''' Opens the wicd GUI ''' + """Opens the wicd GUI""" self.toggle_wicd_gui() - def on_quit(self, widget=None): - ''' Closes the tray icon ''' + """Closes the tray icon""" sys.exit(0) - def on_preferences(self, data=None): - ''' Opens the wicd GUI ''' + """Opens the wicd GUI """ self.toggle_wicd_gui() - def on_about(self, data = None): - ''' Opens the About Dialog ''' + """Opens the About Dialog""" dialog = gtk.AboutDialog() dialog.set_name('wicd tray icon') dialog.set_version('0.4') @@ -362,17 +243,15 @@ class TrayIcon(): dialog.run() dialog.destroy() - def set_from_file(self, path = None): - ''' Sets a new tray icon picture ''' + """Sets a new tray icon picture""" if not self.use_tray: return if path != self.current_icon_path: self.current_icon_path = path gtk.StatusIcon.set_from_file(self, path) - def toggle_wicd_gui(self): - ''' Toggles the wicd GUI ''' + """Toggles the wicd GUI""" if self.gui_win == None: self.gui_win = gui.appGui() elif self.gui_win.is_visible == False: @@ -384,7 +263,7 @@ class TrayIcon(): class DapperTrayIconGUI(TrayIconGUI): def __init__(self, use_tray=True): - ''' initializes the tray icon ''' + """Initializes the tray icon""" TrayIcon.TrayIconGUI.__init__(self) self.use_tray = use_tray if not use_tray: @@ -403,32 +282,31 @@ class TrayIcon(): self.tray.add(self.eb) self.tray.show_all() - def tray_clicked(self, widget, event): - ''' Handles tray mouse click events ''' + """Handles tray mouse click events""" if event.button == 1: self.open_wicd_gui() if event.button == 3: self.menu.popup(None, None, None, event.button, event.time) - - + def set_from_file(self, str): - ''' Calls set_from_file on the gtk.Image for the tray icon ''' + """Calls set_from_file on the gtk.Image for the tray icon""" if not self.use_tray: return self.pic.set_from_file(str) - def set_tooltip(self, str): - ''' - Sets the tooltip for the gtk.ToolTips associated with this - tray icon. - ''' + """ + + Sets the tooltip for the gtk.ToolTips associated with this + tray icon. + + """ if not self.use_tray: return self.tooltip.set_tip(self.eb, str) class EdgyTrayIconGUI(gtk.StatusIcon, TrayIconGUI): - ''' Class for creating the wicd tray icon ''' + """Class for creating the wicd tray icon""" def __init__(self, use_tray=True): TrayIcon.TrayIconGUI.__init__(self) self.use_tray = use_tray @@ -443,17 +321,15 @@ class TrayIcon(): self.set_visible(True) self.connect('activate', self.on_activate) self.connect('popup-menu', self.on_popup_menu) - self.set_from_file("images/no-signal.png") + self.set_from_file(wpath.images + "no-signal.png") self.set_tooltip("Initializing wicd...") - def on_popup_menu(self, status, button, time): - ''' Opens the right click menu for the tray icon ''' + """Opens the right click menu for the tray icon""" self.menu.popup(None, None, None, button, time) - def set_from_file(self, path = None): - ''' Sets a new tray icon picture ''' + """Sets a new tray icon picture""" if not self.use_tray: return if path != self.current_icon_path: self.current_icon_path = path @@ -470,7 +346,6 @@ Arguments: \t-h\t--help\t\tPrint this help. """ - def main(argv): """ The main frontend program. @@ -507,14 +382,12 @@ def main(argv): daemon.SetNeedWiredProfileChooser(False) tray_icon.icon_info.wired_profile_chooser() - # Add dbus signal listener for wired_profile_chooser bus.add_signal_receiver(tray_icon.icon_info.wired_profile_chooser, 'LaunchChooser', 'org.wicd.daemon') - # Run update_tray_icon every 3000ms (3 seconds) - gobject.timeout_add(3000, tray_icon.icon_info.update_tray_icon) + bus.add_signal_receiver(tray_icon.icon_info.update_tray_icon, + 'StatusChanged', 'org.wicd.daemon') - # Enter the main loop mainloop = gobject.MainLoop() mainloop.run()