diff --git a/wicd/gui.py b/wicd/gui.py index 00d9c0a..f49c3f9 100644 --- a/wicd/gui.py +++ b/wicd/gui.py @@ -286,7 +286,11 @@ class appGui(object): def disconnect_all(self, widget=None): """ Disconnects from any active network. """ - daemon.Disconnect() + def handler(*args): + gobject.idle_add(self.network_list.set_sensitive, True) + + self.network_list.set_sensitive(False) + daemon.Disconnect(reply_handler=handler, error_handler=handler) def about_dialog(self, widget, event=None): """ Displays an about dialog. """ @@ -649,19 +653,41 @@ class appGui(object): return False return True + def _wait_for_connect_thread_start(self): + self.wTree.get_widget("progressbar").pulse() + if not self._connect_thread_started: + return True + else: + misc.timeout_add(2, self.update_statusbar) + self.update_statusbar() + return False + def connect(self, widget, nettype, networkid, networkentry): """ Initiates the connection process in the daemon. """ + def handler(*args): + self._connect_thread_started = True + cancel_button = self.wTree.get_widget("cancel_button") cancel_button.set_sensitive(True) + self.network_list.set_sensitive(False) + if self.statusID: + gobject.idle_add(self.status_bar.remove, 1, self.statusID) + gobject.idle_add(self.set_status, language["disconnecting_active"]) + gobject.idle_add(self.status_area.show_all) + self.wait_for_events() + self._connect_thread_started = False if nettype == "wireless": if not self.check_encryption_valid(networkid, networkentry.advanced_dialog): self.edit_advanced(None, None, nettype, networkid, networkentry) return False - wireless.ConnectWireless(networkid) + wireless.ConnectWireless(networkid, reply_handler=handler, + error_handler=handler) elif nettype == "wired": - wired.ConnectWired() - self.update_statusbar() + wired.ConnectWired(reply_handler=handler, error_handler=handler) + + gobject.source_remove(self.update_cb) + misc.timeout_add(100, self._wait_for_connect_thread_start, milli=True) def disconnect(self, widget, nettype, networkid, networkentry): """ Disconnects from the given network. @@ -674,13 +700,18 @@ class appGui(object): networkentry -- The NetworkEntry containing the disconnect button. """ + def handler(*args): + gobject.idle_add(self.network_list.set_sensitive, True) + widget.hide() networkentry.connect_button.show() daemon.SetForcedDisconnect(True) + self.network_list.set_sensitive(False) if nettype == "wired": - wired.DisconnectWired() + wired.DisconnectWired(reply_handler=handler, error_handler=handler) else: - wireless.DisconnectWireless() + wireless.DisconnectWireless(reply_handler=handler, + error_handler=handler) def wait_for_events(self, amt=0): """ Wait for any pending gtk events to finish before moving on. diff --git a/wicd/guiutil.py b/wicd/guiutil.py index 169dcc8..6d103b9 100644 --- a/wicd/guiutil.py +++ b/wicd/guiutil.py @@ -17,11 +17,39 @@ # import gtk +import os.path +import wpath + +HAS_NOTIFY = True +try: + import pynotify + if not pynotify.init("Wicd"): + print 'Could not initalize pynotify' + HAS_NOTIFY = False +except ImportError: + print "Importing pynotify failed, notifications disabled." + HAS_NOTIFY = False + +print "Has notifications support", HAS_NOTIFY + +if wpath.no_use_notifications: + print 'Notifications disabled during setup.py configure' + +def can_use_notify(): + use_notify = os.path.exists(os.path.join(os.path.expanduser('~/.wicd'), + 'USE_NOTIFICATIONS') + ) + return use_notify and HAS_NOTIFY and not wpath.no_use_notifications + def error(parent, message, block=True): """ Shows an error dialog. """ def delete_event(dialog, id): dialog.destroy() + if can_use_notify() and not block: + notification = pynotify.Notification("ERROR", message, "error") + notification.show() + return dialog = gtk.MessageDialog(parent, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK) dialog.set_markup(message) diff --git a/wicd/misc.py b/wicd/misc.py index b5600b2..2dde1d4 100644 --- a/wicd/misc.py +++ b/wicd/misc.py @@ -492,7 +492,7 @@ def stringToNone(text): def checkboxTextboxToggle(checkbox, textboxes): for textbox in textboxes: textbox.set_sensitive(checkbox.get_active()) - + def threaded(f): """ A decorator that will make any function run in a new thread. """ diff --git a/wicd/monitor.py b/wicd/monitor.py index 4accb0e..2937360 100755 --- a/wicd/monitor.py +++ b/wicd/monitor.py @@ -174,6 +174,9 @@ class ConnectionStatus(object): self.iwconfig = '' # Reset this, just in case. self.tried_reconnect = False + bssid = wireless.GetApBssid() + if not bssid: + return False wifi_signal = self._get_printable_sig_strength() if wifi_signal == 0: diff --git a/wicd/networking.py b/wicd/networking.py index 6d439d8..8eaa454 100644 --- a/wicd/networking.py +++ b/wicd/networking.py @@ -154,7 +154,6 @@ class Controller(object): self.disconnect_script = None self.driver = None self.iface = None - self.backend_manager = BackendManager() def get_debug(self): return self._debug def set_debug(self, value): diff --git a/wicd/translations.py b/wicd/translations.py index e5e72f1..948b26d 100644 --- a/wicd/translations.py +++ b/wicd/translations.py @@ -55,7 +55,7 @@ def get_gettext(): _ = lang.gettext return _ -# Generated automatically on Mon, 04 May 2009 23:56:04 CDT +# Generated automatically on Sun, 17 May 2009 19:17:27 CDT _ = get_gettext() language = {} language['resetting_ip_address'] = _('''Resetting IP address...''') @@ -215,3 +215,4 @@ language['disconnected'] = _('''Disconnected''') language['establishing_connection'] = _('''Establishing connection...''') language['association_failed'] = _('''Connection failed: Could not contact the wireless access point.''') language['access_denied'] = _('''Unable to contact the wicd dameon due to an access denied error from DBus. Please check your DBus configuration.''') +language['disconnecting_active'] = _('''Disconnecting active connections...''') diff --git a/wicd/wicd-client.py b/wicd/wicd-client.py index 4934215..97f3095 100755 --- a/wicd/wicd-client.py +++ b/wicd/wicd-client.py @@ -43,16 +43,15 @@ import pango import atexit from dbus import DBusException +import pygtk +pygtk.require('2.0') + HAS_NOTIFY = True try: - import pygtk - pygtk.require('2.0') import pynotify if not pynotify.init("Wicd"): - print 'could not initalize pynotify' HAS_NOTIFY = False except ImportError: - print 'import failed' HAS_NOTIFY = False # Wicd specific imports @@ -60,7 +59,7 @@ from wicd import wpath from wicd import misc from wicd import gui from wicd import dbusmanager -from wicd.guiutil import error +from wicd.guiutil import error, can_use_notify from wicd.translations import language @@ -75,11 +74,6 @@ if not hasattr(gtk, "StatusIcon"): print 'Unable to load tray icon: Missing both egg.trayicon and gtk.StatusIcon modules.' ICON_AVAIL = False -print "Has notifications support", HAS_NOTIFY - -if wpath.no_use_notifications: - print 'Notifications disabled during setup.py configure' - misc.RenameProcess("wicd-client") if __name__ == '__main__': @@ -163,10 +157,6 @@ class TrayIcon(object): self.last_state = None self.should_notify = True - self.use_notify = os.path.exists(os.path.join( - os.path.expanduser('~/.wicd'), - 'USE_NOTIFICATIONS')) - if DBUS_AVAIL: self.update_tray_icon() else: @@ -272,10 +262,8 @@ class TrayIcon(object): [state, info] = daemon.GetConnectionStatus() # should this state change display a notification? - self.should_notify = not wpath.no_use_notifications and \ - (self.last_state != state) and \ - HAS_NOTIFY and \ - self.use_notify + self.should_notify = (can_use_notify() and + self.last_state != state) self.last_state = state diff --git a/wicd/wicd-daemon.py b/wicd/wicd-daemon.py index e0230d9..4b72e99 100644 --- a/wicd/wicd-daemon.py +++ b/wicd/wicd-daemon.py @@ -1300,6 +1300,7 @@ class WiredDaemon(dbus.service.Object): self.daemon = daemon self.wired = wired self._debug_mode = debug + self._cur_wired_prof_name = "" self.WiredNetwork = {} self.config = ConfigManager(os.path.join(wpath.etc, "wired-settings.conf"), @@ -1413,6 +1414,8 @@ class WiredDaemon(dbus.service.Object): self.wired.disconnect_script = self.GetWiredProperty("disconnectscript") self.daemon.wireless_bus.wifi.Disconnect() self.daemon.SetForcedDisconnect(False) + self.UnsetWiredLastUsed() + self.config.set(self._cur_wired_prof_name, "lastused", True, write=True) self.wired.Connect(self.WiredNetwork, debug=self.debug_mode) self.daemon.UpdateState() @@ -1511,8 +1514,10 @@ class WiredDaemon(dbus.service.Object): profile['use_global_dns'] = bool(profile.get('use_global_dns')) profile['use_static_dns'] = bool(profile.get('use_static_dns')) self.WiredNetwork = profile + self._cur_wired_prof_name = profilename return "100: Loaded Profile" else: + self._cur_wired_prof_name = "" self.WiredNetwork = {} return "500: Profile Not Found" diff --git a/wicd/wnettools.py b/wicd/wnettools.py index 317424a..113015f 100644 --- a/wicd/wnettools.py +++ b/wicd/wnettools.py @@ -44,7 +44,7 @@ from misc import find_path _re_mode = (re.I | re.M | re.S) essid_pattern = re.compile('.*ESSID:"?(.*?)"?\s*\n', _re_mode) ap_mac_pattern = re.compile('.*Address: (.*?)\n', _re_mode) -channel_pattern = re.compile('.*Channel:? ?(\d\d?)', _re_mode) +channel_pattern = re.compile('.*Channel:?=? ?(\d\d?)', _re_mode) strength_pattern = re.compile('.*Quality:?=? ?(\d+)\s*/?\s*(\d*)', _re_mode) altstrength_pattern = re.compile('.*Signal level:?=? ?(\d+)\s*/?\s*(\d*)', _re_mode) signaldbm_pattern = re.compile('.*Signal level:?=? ?(-\d\d*)', _re_mode) @@ -83,6 +83,31 @@ def _sanitize_string_strict(string): return translate(str(string), blank_trans, blacklist_strict) else: return string + +_cache = {} +def timedcache(duration=5): + """ A caching decorator for use with wnettools methods. + + Caches the results of a function for a given number of + seconds (defaults to 5). + + """ + def _timedcache(f): + def __timedcache(self, *args, **kwargs): + key = str(args) + str(kwargs) + str(f) + if hasattr(self, 'iface'): + key += self.iface + if (key in _cache and + (time.time() - _cache[key]['time']) < duration): + return _cache[key]['value'] + else: + value = f(self, *args, **kwargs) + _cache[key] = { 'time' : time.time(), 'value' : value } + return value + + return __timedcache + + return _timedcache def GetDefaultGateway(): """ Attempts to determine the default gateway by parsing route -n. """ @@ -349,6 +374,14 @@ class BaseInterface(object): if self.verbose: print cmd misc.Run(cmd) return True + + @timedcache(2) + @neediface("") + def GetIfconfig(self): + """ Runs ifconfig and returns the output. """ + cmd = "ifconfig %s" % self.iface + if self.verbose: print cmd + return misc.Run(cmd) @neediface("") def SetAddress(self, ip=None, netmask=None, broadcast=None): @@ -596,9 +629,7 @@ class BaseInterface(object): """ if not ifconfig: - cmd = 'ifconfig ' + self.iface - if self.verbose: print cmd - output = misc.Run(cmd) + output = self.GetIfconfig() else: output = ifconfig return misc.RunRegex(ip_pattern, output) @@ -635,9 +666,7 @@ class BaseInterface(object): def _slow_is_up(self, ifconfig=None): """ Determine if an interface is up using ifconfig. """ if not ifconfig: - cmd = "ifconfig " + self.iface - if self.verbose: print cmd - output = misc.Run(cmd) + output = self.GetIfconfig() else: output = ifconfig lines = output.split('\n') @@ -800,6 +829,7 @@ class BaseWirelessInterface(BaseInterface): return radiostatus + @timedcache(2) @neediface(False) def GetIwconfig(self): """ Returns the output of iwconfig for this interface. """ @@ -965,12 +995,17 @@ class BaseWirelessInterface(BaseInterface): """ cmd = ['iwconfig', self.iface, 'essid', essid] - if channel and str(channel).isdigit(): - cmd.extend(['channel', str(channel)]) - if bssid: - cmd.extend(['ap', bssid]) if self.verbose: print str(cmd) misc.Run(cmd) + base = "iwconfig %s" % self.iface + if channel and str(channel).isdigit(): + cmd = "%s channel %s" % (base, str(channel)) + if self.verbose: print cmd + misc.Run(cmd) + if bssid: + cmd = "%s ap %s" % (base, bssid) + if self.verbose: print cmd + misc.Run(cmd) def GeneratePSK(self, network): """ Generate a PSK using wpa_passphrase. @@ -1237,9 +1272,7 @@ class BaseWirelessInterface(BaseInterface): def GetBSSID(self, iwconfig=None): """ Get the MAC address for the interface. """ if not iwconfig: - cmd = 'iwconfig ' + self.iface - if self.verbose: print cmd - output = misc.Run(cmd) + output = self.GetIwconfig() else: output = iwconfig @@ -1250,9 +1283,7 @@ class BaseWirelessInterface(BaseInterface): def GetCurrentBitrate(self, iwconfig=None): """ Get the current bitrate for the interface. """ if not iwconfig: - cmd = 'iwconfig ' + self.iface - if self.verbose: print cmd - output = misc.Run(cmd) + output = self.GetIwconfig() else: output = iwconfig @@ -1263,9 +1294,7 @@ class BaseWirelessInterface(BaseInterface): def GetOperationalMode(self, iwconfig=None): """ Get the operational mode for the interface. """ if not iwconfig: - cmd = 'iwconfig ' + self.iface - if self.verbose: print cmd - output = misc.Run(cmd) + output = self.GetIwconfig() else: output = iwconfig @@ -1313,9 +1342,7 @@ class BaseWirelessInterface(BaseInterface): """ if not iwconfig: - cmd = 'iwconfig ' + self.iface - if self.verbose: print cmd - output = misc.Run(cmd) + output = self.GetIwconfig() else: output = iwconfig return self._get_link_quality(output) @@ -1329,9 +1356,7 @@ class BaseWirelessInterface(BaseInterface): """ if not iwconfig: - cmd = 'iwconfig ' + self.iface - if self.verbose: print cmd - output = misc.Run(cmd) + output = self.GetIwconfig() else: output = iwconfig signaldbm_pattern = re.compile('.*Signal level:?=? ?(-\d\d*)', @@ -1348,9 +1373,7 @@ class BaseWirelessInterface(BaseInterface): """ if not iwconfig: - cmd = 'iwconfig ' + self.iface - if self.verbose: print cmd - output = misc.Run(cmd) + output = self.GetIwconfig() else: output = iwconfig network = misc.RunRegex(re.compile('.*ESSID:"(.*?)"',