diff --git a/curses/README b/curses/README new file mode 100644 index 0000000..7586196 --- /dev/null +++ b/curses/README @@ -0,0 +1,28 @@ +This is a curses-based client for wicd. It is designed to imitate wicd-client +as much as can be done with a console-based interface. It is written using the +Urwid (http://excess.org/urwid) toolkit, and thus requires it. + +That's all there is to it, really. It's not going to install itself until I +work on it more and figure out how to use distutils. + +Right now, it lists current available networks, and whether you are connected +to anything or not, all of which is updated in real time. It will actually +connect you to networks now. Global preferences are now configurable from the +console. Per-network settings is a work in progress. + +Controls: + +F5 : refresh wireless networks +F8 or Q: quit +D : disconnect from active network +ESC : if connecting to a network, stop doing so +ENTER : Attempt connection to selected network +P : Display preferences dialog +A : Display "About" dialog + +IN DIALOGS: +ESC or Q: Quit dialog without saving information (if present) + + + +~NaCl diff --git a/curses/TODO b/curses/TODO new file mode 100644 index 0000000..1c80fde --- /dev/null +++ b/curses/TODO @@ -0,0 +1,17 @@ +Things to do (in no particular order): + +* Make a network config dialog for both wireless and wired interfaces +* Make an about dialog +* Implement a keyhandler function for the overall frame + * Make keystrokes customizable +* Make color schemes customizable +* Integrate this with the my local copy of the experimental branch +* Give some indication of activity during the connection process +* Make a man page for the UI. + +Oh, and most importantly: + +* Tell people how they can quit the app in the app (F8 or Q, until I do all of + that stuff) :-) + +Anything else? That's all I can think of now. diff --git a/curses/curses_misc.py b/curses/curses_misc.py new file mode 100644 index 0000000..91d9c2a --- /dev/null +++ b/curses/curses_misc.py @@ -0,0 +1,346 @@ +#!/usr/bin/env python +# -* coding: utf-8 -*- + +""" curses_misc.py: Module for various widgets that are used throughout +wicd-curses. +""" + +# Copyright (C) 2008-9 Andrew Psaltis + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. + +import urwid + +# My savior. :-) +# Although I could have made this myself pretty easily, just want to give credit where +# its due. +# http://excess.org/urwid/browser/contrib/trunk/rbreu_filechooser.py +class SelText(urwid.Text): + """A selectable text widget. See urwid.Text.""" + + def selectable(self): + """Make widget selectable.""" + return True + + + def keypress(self, size, key): + """Don't handle any keys.""" + return key + +class ToggleEdit(urwid.WidgetWrap): + """A edit that can be rendered unselectable by somethhing like a checkbox""" + def __init__(self, caption='', state=True, + attr=('editbx','editfc'),attrnsens='body'): + """ + caption : the Edit's caption + state : the Edit's current sensitivity + attr : tuple of (attr_no_focus, attr_focus) + attrnsens: attr to use when not sensitive + """ + edit = urwid.Edit(caption) + curattr = attr[0] if state == True else attrnsens + w = urwid.AttrWrap(edit,curattr,attr[1]) + self.sensitive=state + self.__super.__init__(w) + + # Kinda like the thing in PyGTK + def set_sensitive(self,state): + self.sensitive=state + if state: + self._w.set_attr('editbx') + else: + self._w.set_attr('body') + + def set_edit_text(self,text): + self._w.set_edit_text(text) + + def get_edit_text(self): + return self._w.get_edit_text() + + # If we aren't sensitive, don't be selectable + def selectable(self): + return self.sensitive + + # Do what an edit does with keys + def keypress(self,size,key): + return self._w.keypress(size,key) + +# Tabbed interface, mostly for use in the Preferences Dialog +class TabColumns(urwid.WidgetWrap): + """ + titles_dict = dictionary of tab_contents (a SelText) : tab_widget (box) + attr = normal attributes + attrsel = attribute when active + """ + def __init__(self,tab_str,tab_wid,title,bottom_part,attr=('body','focus'), + attrsel='tab active', attrtitle='header'): + self.bottom_part = bottom_part + #title_wid = urwid.Text((attrtitle,title),align='right') + column_list = [] + for w in tab_str: + text,trash = w.get_text() + column_list.append(('fixed',len(text),w)) + column_list.append(urwid.Text((attrtitle,title),align='right')) + + self.tab_map = dict(zip(tab_str,tab_wid)) + self.active_tab = tab_str[0] + self.columns = urwid.Columns(column_list,dividechars=1) + #walker = urwid.SimpleListWalker([self.columns,tab_wid[0]]) + #self.listbox = urwid.ListBox(walker) + self.gen_pile(tab_wid[0],True) + self.frame = urwid.Frame(self.pile) + self.__super.__init__(self.frame) + + # Make the pile in the middle + def gen_pile(self,lbox,firstrun=False): + self.pile = urwid.Pile([ + ('fixed',1,urwid.Filler(self.columns,'top')), + urwid.Filler(lbox,'top',height=('relative',99)), + ('fixed',1,urwid.Filler(self.bottom_part,'bottom')) + ]) + if not firstrun: + self.frame.set_body(self.pile) + self.set_w(self.frame) + + def selectable(self): + return True + + def keypress(self,size,key): + self._w.keypress(size,key) + wid = self.pile.get_focus().get_body() + if wid == self.columns: + # lw = self.listbox.body + # lw.pop(1) + self.active_tab.set_attr('body') + self.columns.get_focus().set_attr('tab active') + self.active_tab = self.columns.get_focus() + self.gen_pile(self.tab_map[self.active_tab]) + return key + # self.listbox.body = lw + + +### Combo box code begins here + +class ComboBoxException(Exception): + pass + +# A "combo box" of SelTexts +# I based this off of the code found here: +# http://excess.org/urwid/browser/contrib/trunk/rbreu_menus.py +class ComboBox(urwid.WidgetWrap): + """A ComboBox of text objects""" + class ComboSpace(urwid.WidgetWrap): + """The actual menu-like space that comes down from the ComboText""" + def __init__(self,list,body,ui,show_first=0,pos=(0,0),attr=('body','focus')): + """ + body : parent widget + list : stuff to include in the combobox + ui : the screen + show_first: index of the element in the list to pick first + pos : a tuple of (row,col) where to put the list + attr : a tuple of (attr_no_focus,attr_focus) + """ + + #Calculate width and height of the menu widget: + height = len(list) + width = 0 + for entry in list: + if len(entry) > width: + width = len(entry) + content = [urwid.AttrWrap(SelText(w), attr[0], attr[1]) + for w in list] + self._listbox = urwid.ListBox(content) + + overlay = urwid.Overlay(self._listbox, body, ('fixed left', pos[0]), + width + 2, ('fixed top', pos[1]), height) + self.__super.__init__(overlay) + + def show(self,ui,display): + + dim = ui.get_cols_rows() + keys = True + + #Event loop: + while True: + if keys: + ui.draw_screen(dim, self.render(dim, True)) + + keys = ui.get_input() + + if "window resize" in keys: + dim = ui.get_cols_rows() + if "esc" in keys: + return None + if "enter" in keys: + (wid,pos) = self._listbox.get_focus() + (text,attr) = wid.get_text() + return text + + for k in keys: + #Send key to underlying widget: + self._w.keypress(dim, k) + + #def get_size(self): + + def __init__(self,label='',list=[],attr=('body','focus'),use_enter=True,show_first=0): + """ + label : bit of text that preceeds the combobox. If it is "", then + ignore it + list : stuff to include in the combobox + body : parent widget + ui : the screen + row : where this object is to be found onscreen + show_first: index of the element in the list to pick first + """ + + self.label = urwid.Text(label) + self.attr = attr + self.list = list + str,trash = self.label.get_text() + + self.overlay = None + + self.cbox = urwid.AttrWrap(SelText(' vvv'),attr[0],attr[1]) + # Unicode will kill me sooner or later. ^_^ + if label != '': + w = urwid.Columns([('fixed',len(str),self.label),self.cbox],dividechars=1) + else: + w = urwid.Columns([self.cbox]) + self.__super.__init__(w) + + # We need this to pick our keypresses + self.use_enter = use_enter + + # Set the focus at the beginning to 0 + self.show_first = show_first + + def set_list(self,list): + self.list = list + + def set_show_first(self,show_first): + self.show_first = show_first + + def build_combobox(self,body,ui,row,show_first=0): + str,trash = self.label.get_text() + self.cbox = urwid.AttrWrap(SelText([self.list[show_first]+' vvv']), + self.attr[0],self.attr[1]) + if str != '': + w = urwid.Columns([('fixed',len(str),self.label),self.cbox],dividechars=1) + self.overlay = self.ComboSpace(self.list,body,ui,self.show_first, + pos=(len(str)+1,row)) + else: + w = urwid.Columns([self.cbox]) + self.overlay = self.ComboSpace(self.list,body,ui,self.show_first, + pos=(0,row)) + + self.set_w(w) + self.body = body + self.ui = ui + + # If we press space or enter, be a combo box! + def keypress(self,size,key): + activate = key == ' ' + if self.use_enter: + activate = activate or key == 'enter' + if activate: + # Die if the user didn't prepare the combobox overlay + if self.overlay == None: + raise ComboBoxException('ComboBox must be built before use!') + retval = self.overlay.show(self.ui,self.body) + if retval != None: + self.cbox.set_w(SelText(retval+' vvv')) + return self._w.keypress(size,key) + + # Most obvious thing ever. :-) + def selectable(self): + return True + + # Return the index of the selected element + def get_selected(self): + wid,pos = self.overlay._listbox.get_focus() + return pos + + +# Almost completely ripped from rbreu_filechooser.py: +# http://excess.org/urwid/browser/contrib/trunk/rbreu_menus.py +class Dialog(urwid.WidgetWrap): + """ + Creates a BoxWidget that displays a message + + Attributes: + + b_pressed -- Contains the label of the last button pressed or None if no + button has been pressed. + edit_text -- After a button is pressed, this contains the text the user + has entered in the edit field + """ + + b_pressed = None + edit_text = None + + _blank = urwid.Text("") + _edit_widget = None + _mode = None + + def __init__(self, msg, buttons, attr, width, height, body, ): + """ + msg -- content of the message widget, one of: + plain string -- string is displayed + (attr, markup2) -- markup2 is given attribute attr + [markupA, markupB, ... ] -- list items joined together + buttons -- a list of strings with the button labels + attr -- a tuple (background, button, active_button) of attributes + width -- width of the message widget + height -- height of the message widget + body -- widget displayed beneath the message widget + """ + + # Text widget containing the message: + msg_widget = urwid.Padding(urwid.Text(msg), 'center', width - 4) + + # GridFlow widget containing all the buttons: + button_widgets = [] + + for button in buttons: + button_widgets.append(urwid.AttrWrap( + urwid.Button(button, self._action), attr[1], attr[2])) + + button_grid = urwid.GridFlow(button_widgets, 12, 2, 1, 'center') + + # Combine message widget and button widget: + widget_list = [msg_widget, self._blank, button_grid] + self._combined = urwid.AttrWrap(urwid.Filler( + urwid.Pile(widget_list, 2)), attr[0]) + + # This was the real thing I added to this class + self._linebox = urwid.LineBox(self._combined) + # Place the dialog widget on top of body: + # Width and height are increased to accomidate the linebox + overlay = urwid.Overlay(self._linebox, body, 'center', width+2, + 'middle', height+2) + + urwid.WidgetWrap.__init__(self, overlay) + + + def _action(self, button): + """ + Function called when a button is pressed. + Should not be called manually. + """ + + self.b_pressed = button.get_label() + if self._edit_widget: + self.edit_text = self._edit_widget.get_edit_text() diff --git a/curses/prefs_curses.py b/curses/prefs_curses.py new file mode 100644 index 0000000..3dd275a --- /dev/null +++ b/curses/prefs_curses.py @@ -0,0 +1,466 @@ +#!/usr/bin/env python + +# Copyright (C) 2008-9 Andrew Psaltis + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. + +import urwid +import urwid.curses_display + +from wicd import misc +from wicd import dbusmanager +from curses_misc import SelText,ToggleEdit,ComboBox,TabColumns + +daemon = None +wireless = None +wired = None +# Will work for now, I guess. +language = misc.get_language_list_gui() + +class PrefsDialog(urwid.WidgetWrap): + def __init__(self,body,pos,ui,dbus=None): + global daemon, wireless, wired + + daemon = dbus['daemon'] + wireless = dbus['wireless'] + wired = dbus['wired'] + + width,height = ui.get_cols_rows() + height -= 3 + #width = 80 + #height = 20 + # Stuff that goes at the top + + header0_t = language["gen_settings"] + header1_t = language["ext_programs"] + header2_t = language["advanced_settings"] + self.header0 = urwid.AttrWrap(SelText(header0_t),'tab active','focus') + self.header1 = urwid.AttrWrap(SelText(header1_t),'body','focus') + self.header2 = urwid.AttrWrap(SelText(header2_t),'body','focus') + title = language['preferences'] + + # Blank line + _blank = urwid.Text('') + + #### + #### Text in the widgets + #### + + # General Settings + net_cat_t = ('header','Network Interfaces') + wired_t = ('editcp',language['wired_interface']+': ') + wless_t = ('editcp',language['wireless_interface']+':') + always_show_wired_t = 'Always show wired interface' + + global_dns_cat_t = ('header','Global DNS Servers') + global_dns_t = ('editcp',language['use_global_dns']) + dns_dom_t = ('editcp',' DNS Domain: ') + search_dom_t = ('editcp',' Search domain:') + dns1_t = ('editcp',' DNS server 1: ') + dns2_t = ('editcp',' DNS server 2: ') + dns3_t = ('editcp',' DNS server 3: ') + + + wired_auto_cat_t= ('header','Wired Autoconnect Settings') + wired_auto_1_t = language['use_default_profile'] + wired_auto_2_t = language['show_wired_list'] + wired_auto_3_t = language['use_last_used_profile'] + + #### External Programs + automatic_t = language['wicd_auto_config'] + + dhcp_header_t = ('header',language["dhcp_client"]) + # Automatic + dhcp1_t = 'dhclient' + dhcp2_t = 'dhcpcd' + dhcp3_t = 'pump' + + wired_detect_header_t = ('header',language["wired_detect"]) + wired1_t = 'ethtool' + wired2_t = 'mii-tool' + + flush_header_t = ('header',language["route_flush"]) + flush1_t = 'ip' + flush2_t = 'route' + + #### Advanced Settings + #wpa_t=('editcp',language['wpa_supplicant_driver']+':') + wpa_cat_t=('header','WPA_Supplicant') + wpa_t=('editcp','Driver:') + wpa_list = ['spam','double spam','triple spam','quadruple spam'] + wpa_warn_t = ('important','You should almost always use wext as the WPA Supplicant Driver') + + backend_cat_t = ('header',language['backend']) + backend_t = language['backend']+':' + backend_list = ['spam','double spam','triple spam','quadruple spam'] + + debug_cat_t = ('header','Debugging') + debug_mode_t = language['use_debug_mode'] + + wless_cat_t = ('header','Wireless Interface') + use_dbm_t = language['display_type_dialog'] + + auto_reconn_cat_t = ('header','Automatic Reconnect') + auto_reconn_t = 'Automatically reconnect on connection loss' + + + #### + #### UI Widgets + #### + + # General Settings + self.net_cat = urwid.Text(net_cat_t) + self.wired_edit = urwid.AttrWrap(urwid.Edit(wired_t),'editbx','editfc') + self.wless_edit = urwid.AttrWrap(urwid.Edit(wless_t),'editbx','editfc') + + self.global_dns_cat = urwid.Text(global_dns_cat_t) + # Default the global DNS settings to off. They will be reenabled later + # if so required. + global_dns_state = False + self.global_dns_checkb = urwid.CheckBox(global_dns_t,global_dns_state, + on_state_change=self.global_dns_trigger) + self.search_dom = ToggleEdit(search_dom_t,global_dns_state) + self.dns_dom = ToggleEdit(dns_dom_t,global_dns_state) + self.dns1 = ToggleEdit(dns1_t,global_dns_state) + self.dns2 = ToggleEdit(dns2_t,global_dns_state) + self.dns3 = ToggleEdit(dns3_t,global_dns_state) + + self.always_show_wired_checkb = urwid.CheckBox(always_show_wired_t) + + self.wired_auto_l = [] + self.wired_auto_cat = urwid.Text(wired_auto_cat_t) + self.wired_auto_1 = urwid.RadioButton(self.wired_auto_l,wired_auto_1_t) + self.wired_auto_2 = urwid.RadioButton(self.wired_auto_l,wired_auto_2_t) + self.wired_auto_3 = urwid.RadioButton(self.wired_auto_l,wired_auto_3_t) + generalLB = urwid.ListBox([self.net_cat, + self.wless_edit,#_blank, + self.wired_edit, + self.always_show_wired_checkb,_blank, + self.global_dns_cat, + self.global_dns_checkb,#_blank, + self.search_dom,self.dns_dom, + self.dns1,self.dns2,self.dns3,_blank, + self.wired_auto_cat, + self.wired_auto_1, + self.wired_auto_2, + self.wired_auto_3 + ]) + + #### External Programs tab + automatic_t = language['wicd_auto_config'] + + self.dhcp_header = urwid.Text(dhcp_header_t) + self.dhcp_l = [] + # Automatic + self.dhcp0 = urwid.RadioButton(self.dhcp_l,automatic_t) + self.dhcp1 = urwid.RadioButton(self.dhcp_l,dhcp1_t) + self.dhcp2 = urwid.RadioButton(self.dhcp_l,dhcp2_t) + self.dhcp3 = urwid.RadioButton(self.dhcp_l,dhcp3_t) + + self.wired_l = [] + self.wired_detect_header = urwid.Text(wired_detect_header_t) + self.wired0 = urwid.RadioButton(self.wired_l,automatic_t) + self.wired1 = urwid.RadioButton(self.wired_l,wired1_t) + self.wired2 = urwid.RadioButton(self.wired_l,wired2_t) + + self.flush_l = [] + self.flush_header = urwid.Text(flush_header_t) + self.flush0 = urwid.RadioButton(self.flush_l,automatic_t) + self.flush1 = urwid.RadioButton(self.flush_l,flush1_t) + self.flush2 = urwid.RadioButton(self.flush_l,flush2_t) + + externalLB = urwid.ListBox([self.dhcp_header, + self.dhcp0,self.dhcp1,self.dhcp2,self.dhcp3, + _blank, + self.wired_detect_header, + self.wired0,self.wired1,self.wired2, + _blank, + self.flush_header, + self.flush0,self.flush1,self.flush2 + ]) + + + #### Advanced settings + self.wpa_cat = urwid.Text(wpa_cat_t) + self.wpa_cbox = ComboBox(wpa_t) + self.wpa_warn = urwid.Text(wpa_warn_t) + + self.backend_cat = urwid.Text(backend_cat_t) + self.backend_cbox = ComboBox(backend_t) + + self.debug_cat = urwid.Text(debug_cat_t) + self.debug_mode_checkb = urwid.CheckBox(debug_mode_t) + + self.wless_cat = urwid.Text(wless_cat_t) + self.use_dbm_checkb = urwid.CheckBox(use_dbm_t) + + self.auto_reconn_cat = urwid.Text(auto_reconn_cat_t) + self.auto_reconn_checkb = urwid.CheckBox(auto_reconn_t) + + advancedLB = urwid.ListBox([self.wpa_cat, + self.wpa_cbox,self.wpa_warn,_blank, + self.backend_cat, + self.backend_cbox,_blank, + self.debug_cat, + self.debug_mode_checkb, _blank, + self.wless_cat, + self.use_dbm_checkb, _blank, + self.auto_reconn_cat, + self.auto_reconn_checkb]) + + + headerList = [self.header0,self.header1,self.header2] + lbList = [generalLB,externalLB,advancedLB] + self.tab_map = {self.header0 : generalLB, + self.header1 : externalLB, + self.header2 : advancedLB} + #self.load_settings() + + # Now for the buttons: + ok_t = 'OK' + cancel_t = 'Cancel' + + ok_button = urwid.AttrWrap(urwid.Button('OK',self.ok_callback),'body','focus') + cancel_button = urwid.AttrWrap(urwid.Button('Cancel',self.cancel_callback),'body','focus') + # Variables set by the buttons' callback functions + self.CANCEL_PRESSED = False + self.OK_PRESSED = False + + + self.button_cols = urwid.Columns([ok_button,cancel_button],dividechars=1) + #self.active_tab = self.header0 + + #self.columns = urwid.Columns([('fixed',len(header0_t),self.header0), + # ('fixed',len(header1_t),self.header1), + # ('fixed',len(header2_t),self.header2), + # urwid.Text(('header',title),align='right')], + # dividechars=1) + + #content = [self.columns,generalPile] + #self._label = urwid.AttrWrap(SelText(titles),attr[0],attr[1]) + #self.walker = urwid.SimpleListWalker(content) + #self.listbox = urwid.ListBox(self.walker) + #self._linebox = urwid.LineBox(self._listbox) + self.tabs = TabColumns(headerList,lbList,'Preferences',self.button_cols) + #overlay = urwid.Overlay(self.tabs, body, ('fixed left', pos[0]), + # width, ('fixed top', pos[1]), height) + self.__super.__init__(self.tabs) + + def load_settings(self): + ### General Settings + # Urwid does not like dbus.Strings as text markups + wless_iface = unicode(daemon.GetWirelessInterface()) + wired_iface = unicode(daemon.GetWiredInterface()) + self.wless_edit.set_edit_text(wless_iface) + self.wired_edit.set_edit_text(wired_iface) + + self.always_show_wired_checkb.set_state( + daemon.GetAlwaysShowWiredInterface()) + + # DNS + self.global_dns_checkb.set_state(daemon.GetUseGlobalDNS()) + theDNS = daemon.GetGlobalDNSAddresses() + + i = 0 + for w in self.dns1,self.dns2,self.dns3,self.dns_dom,self.search_dom : + w.set_edit_text(misc.noneToBlankString(theDNS[i])) + i+=1 + + # Wired Automatic Connection + self.wired_auto_l[daemon.GetWiredAutoConnectMethod()-1] + + ### External Programs + dhcp_method = daemon.GetDHCPClient() + self.dhcp_l[dhcp_method].set_state(True) + + wired_link_method = daemon.GetLinkDetectionTool() + self.wired_l[wired_link_method].set_state(True) + + flush_method = daemon.GetFlushTool() + self.flush_l[flush_method].set_state(True) + + ### Advanced settings + # wpa_supplicant janx + self.wpadrivers = ["wext", "hostap", "madwifi", "atmel", + "ndiswrapper", "ipw"] + self.wpadrivers = wireless.GetWpaSupplicantDrivers(self.wpadrivers) + self.wpadrivers.append("ralink_legacy") + # Same as above with the dbus.String + self.thedrivers = [unicode(w) for w in self.wpadrivers] + self.wpa_cbox.set_list(self.thedrivers) + + # Pick where to begin first: + def_driver = daemon.GetWPADriver() + try: + self.wpa_cbox.set_show_first(self.wpadrivers.index(def_driver)) + except ValueError: + pass # It defaults to 0 anyway + + self.backends = daemon.GetBackendList() + # Remove the blank string b/c of some dbus mess + self.backends.remove('') + self.thebackends= [unicode(w) for w in self.backends] + self.backend_cbox.set_list(self.thebackends) + + # Three last checkboxes + self.debug_mode_checkb.set_state(daemon.GetDebugMode()) + self.use_dbm_checkb.set_state(daemon.GetSignalDisplayType()) + self.auto_reconn_checkb.set_state(daemon.GetAutoReconnect()) + + def save_results(self): + """ Pushes the selected settings to the daemon. + This exact order is found in prefs.py""" + daemon.SetUseGlobalDNS(self.global_dns_checkb.get_state()) + daemon.SetGlobalDNS(self.dns1.get_edit_text(), self.dns2.get_edit_text(), + self.dns3.get_edit_text(), self.dns_dom.get_edit_text(), + self.search_dom.get_edit_text()) + daemon.SetWirelessInterface(self.wless_edit.get_edit_text()) + daemon.SetWiredInterface(self.wired_edit.get_edit_text()) + daemon.SetWPADriver(self.wpadrivers[self.wpa_cbox.get_selected()]) + daemon.SetAlwaysShowWiredInterface(self.always_show_wired_checkb.get_state()) + daemon.SetAutoReconnect(self.auto_reconn_checkb.get_state()) + daemon.SetDebugMode(self.debug_mode_checkb.get_state()) + daemon.SetSignalDisplayType(int(self.use_dbm_checkb.get_state())) + if self.wired_auto_2.get_state(): + daemon.SetWiredAutoConnectMethod(2) + elif self.wired_auto_3.get_state(): + daemon.SetWiredAutoConnectMethod(3) + else: + daemon.SetWiredAutoConnectMethod(1) + + daemon.SetBackend(self.backends[self.backend_cbox.get_selected()]) + + # External Programs Tab + if self.dhcp0.get_state(): + dhcp_client = misc.AUTO + elif self.dhcp1.get_state(): + dhcp_client = misc.DHCLIENT + elif self.dhcp2.get_state(): + dhcp_client = misc.DHCPCD + else: + dhcp_client = misc.PUMP + daemon.SetDHCPClient(dhcp_client) + + if self.wired0.get_state(): + link_tool = misc.AUTO + elif self.wired1.get_state(): + link_tool = misc.ETHTOOL + else: + link_tool = misc.MIITOOL + daemon.SetLinkDetectionTool(link_tool) + + if self.flush0.get_state(): + flush_tool = misc.AUTO + elif self.flush1.get_state(): + flush_tool = misc.IP + else: + flush_tool = misc.ROUTE + daemon.SetFlushTool(flush_tool) + + # DNS CheckBox callback + def global_dns_trigger(self,check_box,new_state,user_data=None): + for w in self.dns1,self.dns2,self.dns3,self.dns_dom,self.search_dom: + w.set_sensitive(new_state) + + # Button callbacks + def ok_callback(self,button_object,user_data=None): + self.OK_PRESSED = True + def cancel_callback(self,button_object,user_data=None): + self.CANCEL_PRESSED = True + + def ready_comboboxes(self,ui,body): + self.wpa_cbox.build_combobox(body,ui,4) + self.backend_cbox.build_combobox(body,ui,8) + + # Put the widget into an overlay, and run! + def run(self,ui, dim, display): + width,height = ui.get_cols_rows() + self.load_settings() + # TODO: The below, if things go 'well' + # If we are small, "tabbify" the interface + # Else, pile it together + + overlay = urwid.Overlay(self.tabs, display, ('fixed left', 0),width + , ('fixed top',1), height-3) + self.ready_comboboxes(ui,overlay) + + keys = True + while True: + if keys: + ui.draw_screen(dim, overlay.render(dim, True)) + keys = ui.get_input() + + if "window resize" in keys: + dim = ui.get_cols_rows() + if "esc" in keys or 'Q' in keys: + return False + for k in keys: + #Send key to underlying widget: + overlay.keypress(dim, k) + if self.CANCEL_PRESSED: + return False + if self.OK_PRESSED in keys: + return True + + +### +### EXTERNAL ENTRY POINT STUFF +### +def run_it(): + dialog = PrefsDialog(None,(0,0),ui,dbusmanager.get_dbus_ifaces()) + keys = True + dim = ui.get_cols_rows() + dialog.load_settings() + dialog.ready_comboboxes(ui,dialog) + while True: + if keys: + ui.draw_screen(dim, dialog.render(dim, True)) + keys = ui.get_input() + + if "window resize" in keys: + dim = ui.get_cols_rows() + if "esc" in keys or 'Q' in keys: + return False + for k in keys: + dialog.keypress(dim, k) + if dialog.CANCEL_PRESSED: + return False + if dialog.OK_PRESSED: + dialog.save_results() + return True + +if __name__=='__main__': + try: + dbusmanager.connect_to_dbus() + except DBusException: + # I may need to be a little more verbose here. + # Suggestions as to what should go here + print "Can't connect to the daemon. Are you sure it is running?" + print "Please check the wicd log for error messages." + raise + ui = urwid.curses_display.Screen() + ui.register_palette([ + ('body','light gray','default'), + ('focus','dark magenta','light gray'), + ('header','light blue','default'), + ('important','light red','default'), + ('connected','dark green','default'), + ('connected focus','default','dark green'), + ('editcp', 'default', 'default', 'standout'), + ('editbx', 'light gray', 'dark blue'), + ('editfc', 'white','dark blue', 'bold'), + ('tab active','dark green','light gray')]) + ui.run_wrapper(run_it) diff --git a/curses/wicd-curses.py b/curses/wicd-curses.py new file mode 100644 index 0000000..aa5ac35 --- /dev/null +++ b/curses/wicd-curses.py @@ -0,0 +1,625 @@ +#!/usr/bin/env python + +""" wicd-curses -- a (curses-based) console interface to wicd + +Provides the a console UI for wicd, so that people with broken X servers can +at least get a network connection. Or those who don't like using X. :-) + +""" + +# Copyright (C) 2008-9 Andrew Psaltis + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. + +""" + This contains/will contain A LOT of code from the other parts of wicd. + + This is probably due to the fact that I did not really know what I was doing + when I started writing this. It works, so I guess that's all that matters. + + Comments, criticisms, patches, bug reports all welcome! +""" + +# UI stuff +#import urwid.raw_display +import urwid.curses_display +import urwid + +# DBus communication stuff +from dbus import DBusException +from dbus import version as dbus_version +# It took me a while to figure out that I have to use this. +import gobject + +# Other important wicd-related stuff +import wicd.misc as misc +from wicd import dbusmanager + +# Internal Python stuff +import sys +from time import sleep + +# Curses UIs for other stuff +from curses_misc import SelText,ComboBox,Dialog +import prefs_curses +from prefs_curses import PrefsDialog + +language = misc.get_language_list_gui() +# Whew. Now on to more interesting stuff: + +######################################## +##### SUPPORT CLASSES +######################################## +# A hack to get any errors that pop out of the program to appear ***AFTER*** the +# program exits. +# I also may have been a bit overkill about using this too, I guess I'll find +# that out soon enough. +# I learned about this from this example: +# http://blog.lutzky.net/2007/09/16/exception-handling-decorators-and-python/ +class wrap_exceptions: + def __call__(self, f): + def wrap_exceptions(*args, **kargs): + try: + return f(*args, **kargs) + except KeyboardInterrupt: + gobject.source_remove(redraw_tag) + loop.quit() + ui.stop() + print "\nTerminated by user." + raise + except : + # If the UI isn't inactive (redraw_tag wouldn't normally be + # set), then don't try to stop it, just gracefully die. + if redraw_tag != -1: + # Remove update_ui from the event queue + gobject.source_remove(redraw_tag) + # Quit the loop + loop.quit() + # Zap the screen + ui.stop() + # Print out standard notification: + print "\nEXCEPTION!" + print "Please report this to the maintainer and/or file a bug report with the backtrace below:" + print redraw_tag + # Flush the buffer so that the notification is always above the + # backtrace + sys.stdout.flush() + # Raise the exception + #sleep(2) + raise + + return wrap_exceptions + +######################################## +##### SUPPORT FUNCTIONS +######################################## + +# Look familiar? These two functions are clones of functions found in wicd's +# gui.py file, except that now set_status is a function passed to them. +@wrap_exceptions() +def check_for_wired(wired_ip,set_status): + """ Determine if wired is active, and if yes, set the status. """ + if wired_ip and wired.CheckPluggedIn(): + set_status(language['connected_to_wired'].replace('$A',wired_ip)) + return True + else: + return False + +@wrap_exceptions() +def check_for_wireless(iwconfig, wireless_ip, set_status): + """ Determine if wireless is active, and if yes, set the status. """ + if not wireless_ip: + return False + + network = wireless.GetCurrentNetwork(iwconfig) + if not network: + return False + + network = str(network) + if daemon.GetSignalDisplayType() == 0: + strength = wireless.GetCurrentSignalStrength(iwconfig) + else: + strength = wireless.GetCurrentDBMStrength(iwconfig) + + if strength is None: + return False + strength = str(strength) + ip = str(wireless_ip) + set_status(language['connected_to_wireless'].replace + ('$A', network).replace + ('$B', daemon.FormatSignalForPrinting(strength)).replace + ('$C', wireless_ip)) + return True + + +# Self explanitory, and not used until I can get some list sort function +# working... +# Also defunct. +# Current list header is STR,ESSID,ENCRYPT,BSSID,TYPE,CHANNEL +def gen_list_header(): + return '%3s %4s %s %19s %s ' % ('NUM','STR','BSSID','CHANNEL','ESSID') + +# Generate the list of networks. +# Mostly borrowed/stolen from wpa_cli, since I had no clue what all of those +# DBUS interfaces do. ^_^ +# Whatever calls this must be exception-wrapped if it is run if the UI is up +def gen_network_list(): + # Pick which strength measure to use based on what the daemon says + if daemon.GetSignalDisplayType() == 0: + strenstr = 'quality' + gap = 3 + else: + strenstr = 'strength' + gap = 5 + + id = 0 + wiredL = [] + for profile in wired.GetWiredProfileList(): + theString = '%4s %25s' % (id, profile) + #### THIS IS wired.blah() in experimental + #print config.GetLastUsedWiredNetwork() + # Tag if no wireless IP present, and wired one is + is_active = wireless.GetWirelessIP('') == None and wired.GetWiredIP('') != None + if is_active: + theString = '>'+theString[1:] + + #wiredL.append(urwid.AttrWrap(SelText(theString),'connected', + # 'connected focus')) + #else: + # wiredL.append(urwid.AttrWrap(SelText(theString),'body','focus')) + wiredL.append(theString) + id+=1 + + wlessL = [] + for network_id in range(0, wireless.GetNumberOfNetworks()): + # ?: in python + encryption = wireless.GetWirelessProperty(network_id, 'encryption_method') if wireless.GetWirelessProperty(network_id, 'encryption') else 'Unsecured' + theString = ' %*s %25s %9s %17s %6s: %s' % ( gap, + daemon.FormatSignalForPrinting( + str(wireless.GetWirelessProperty(network_id, strenstr))), + wireless.GetWirelessProperty(network_id, 'essid'), + #wireless.GetWirelessProperty(network_id, 'encryption_method'), + encryption, + wireless.GetWirelessProperty(network_id, 'bssid'), + wireless.GetWirelessProperty(network_id, 'mode'), # Master, Ad-Hoc + wireless.GetWirelessProperty(network_id, 'channel') + ) + is_active = wireless.GetCurrentSignalStrength("") != 0 and wireless.GetCurrentNetworkID(wireless.GetIwconfig())==network_id + if is_active: + theString = '>'+theString[1:] + wlessL.append(urwid.AttrWrap(SelText(theString),'connected','connected focus')) + else: + wlessL.append(urwid.AttrWrap(SelText(theString),'body','focus')) + return (wiredL,wlessL) + +def about_dialog(body): + # This looks A LOT better when it is actually displayed. I promise :-). + # The ASCII Art "Wicd" was made from the "smslant" font on one of those + # online ASCII big text generators. + theText = [ +('green'," /// \\\\\\")," _ ___ __\n", +('green'," /// \\\\\\")," | | /| / (_)______/ /\n", +('green'," /// \\\\\\")," | |/ |/ / / __/ _ / \n", +('green',"/|| // \\\\ ||\\")," |__/|__/_/\__/\_,_/ \n", +('green',"||| ||"),"(|^|)",('green',"|| |||"), +" ($VERSION) \n".replace("$VERSION",daemon.Hello()), + +('green',"\\|| \\\\")," |+| ",('green',"// ||/ \n"), +('green'," \\\\\\")," |+| ",('green',"///")," http://wicd.net \n", +('green'," \\\\\\")," |+| ",('green',"///")," Brought to you by:\n", +('green'," \\\\\\")," |+| ",('green',"///")," Adam Blackburn (wicd)\n", +" ___|+|___ Dan O'Reilly (wicd)\n", +" |---------| Andrew Psaltis (this ui)\n", +"---------------------------------------------------"] + about = Dialog(theText,['OK'],('body','body','focus'),55,14,body) + + keys = True + dim = ui.get_cols_rows() + while True: + if keys: + ui.draw_screen(dim, about.render(dim, True)) + + keys = ui.get_input() + if "window resize" in keys: + dim = ui.get_cols_rows() + if "esc" in keys: + return False + for k in keys: + about.keypress(dim, k) + if about.b_pressed == 'OK': + return False + +######################################## +##### APPLICATION INTERFACE CLASS +######################################## +# The Whole Shebang +class appGUI(): + """The UI itself, all glory belongs to it!""" + def __init__(self): + self.size = ui.get_cols_rows() + # Happy screen saying that you can't do anything because we're scanning + # for networks. :-) + # Will need a translation sooner or later + self.screen_locker = urwid.Filler(urwid.Text(('important',"Scanning networks... stand by..."), align='center')) + self.TITLE = 'Wicd Curses Interface' + + #wrap1 = urwid.AttrWrap(txt, 'black') + #fill = urwid.Filler(txt) + + header = urwid.AttrWrap(urwid.Text(self.TITLE,align='right'), 'header') + self.wiredH=urwid.Filler(urwid.Text("Wired Network(s)")) + self.wlessH=urwid.Filler(urwid.Text("Wireless Network(s)")) + + wiredL,wlessL = gen_network_list() + self.wiredCB = urwid.Filler(ComboBox(list=wiredL,use_enter=False)) + self.wlessLB = urwid.ListBox(wlessL) + # Stuff I used to simulate large lists + #spam = SelText('spam') + #spamL = [ urwid.AttrWrap( w, None, 'focus' ) for w in [spam,spam,spam, + # spam,spam,spam,spam,spam,spam,spam,spam,spam,spam,spam,spam, + # spam,spam,spam,spam,spam,spam,spam,spam,spam,spam,spam,spam, + # spam,spam,spam,spam,spam,spam,spam,spam,spam,spam,spam,spam, + # spam,spam,spam,spam] ] + #self.spamLB = urwid.ListBox(spamL) + + # Choose whether to show the wired part of the interface. + if daemon.GetAlwaysShowWiredInterface(): + self.thePile = urwid.Pile([('fixed',1,self.wiredH), + ('fixed',1,self.wiredCB), + ('fixed',1,self.wlessH), + self.wlessLB] ) + else: + self.thePile = urwid.Pile([('fixed',1,self.wlessH),self.wlessLB] ) + self.footer1 = urwid.AttrWrap(urwid.Text("Something important will eventually go here."),'body') + self.footer2 = urwid.AttrWrap(urwid.Text("If you are seeing this, then something has gone wrong!"),'important') + self.footerList = urwid.ListBox([self.footer1,self.footer2]) + # Pop takes a number! + #walker.pop(1) + nothingness = urwid.Filler(urwid.Text('Hello, world!')) + self.frame = urwid.Frame(self.thePile, + header=header, + footer=urwid.BoxAdapter(self.footerList,2)) + self.wiredCB.get_body().build_combobox(self.frame,ui,3) + + self.frame.set_body(self.thePile) + # Booleans gallore! + self.prev_state = False + self.connecting = False + self.screen_locked = False + self.connecting = False + self.always_show_wired = daemon.GetAlwaysShowWiredInterface() + self.update_status() + + #self.dialog = PrefOverlay(self.frame,self.size) + + # Does what it says it does + def lock_screen(self): + self.frame.set_body(self.screen_locker) + self.screen_locked = True + + def unlock_screen(self): + self.update_netlist(force_check=True) + self.frame.set_body(self.thePile) + self.screen_locked = False + # I'm hoping that this will get rid of Adam's problem with the ListBox not + # redisplaying itself immediately upon completion. + self.update_ui() + + # Be clunky until I get to a later stage of development. + # Update the list of networks. Usually called by DBus. + # TODO: Preserve current focus when updating the list. + @wrap_exceptions() + def update_netlist(self,state=None, x=None, force_check=False): + """ Updates the overall network list.""" + if not state: + state, x = daemon.GetConnectionStatus() + if self.prev_state != state or force_check: + wiredL,wlessL = gen_network_list() + #self.wiredCB = urwid.Filler(ComboBox(wiredL,self.frame,ui,3, + # use_enter=False)) + self.wiredCB.get_body().set_list(wiredL) + self.wiredCB.get_body().build_combobox(self.frame,ui,3) + self.wlessLB.body = urwid.SimpleListWalker(wlessL) + # If the "Always Show Wired" part of the interface changes, change + # along with it. + if daemon.GetAlwaysShowWiredInterface() != self.always_show_wired: + if daemon.GetAlwaysShowWiredInterface(): + self.thePile = urwid.Pile([('fixed',1,self.wiredH), + ('fixed',1,self.wiredCB), + ('fixed',1,self.wlessH), + self.wlessLB] ) + else: + self.thePile = urwid.Pile([('fixed',1,self.wlessH),self.wlessLB] ) + self.frame.body = self.thePile + self.always_show_wired = not self.always_show_wired + self.prev_state = state + + # Update the footer/status bar + @wrap_exceptions() + def update_status(self): + wired_connecting = wired.CheckIfWiredConnecting() + wireless_connecting = wireless.CheckIfWirelessConnecting() + self.connecting = wired_connecting or wireless_connecting + + fast = not daemon.NeedsExternalCalls() + if self.connecting: + #self.lock_screen() + #if self.statusID: + # gobject.idle_add(self.status_bar.remove, 1, self.statusID) + if wireless_connecting: + if not fast: + iwconfig = wireless.GetIwconfig() + else: + iwconfig = '' + # set_status is rigged to return false when it is not + # connecting to anything, so this should work. + gobject.idle_add(self.set_status, wireless.GetCurrentNetwork(iwconfig) + + ': ' + + language[str(wireless.CheckWirelessConnectingMessage())], + True ) + if wired_connecting: + gobject.idle_add(self.set_status, language['wired_network'] + + ': ' + + language[str(wired.CheckWiredConnectingMessage())], + True) + return True + else: + if check_for_wired(wired.GetWiredIP(''),self.set_status): + return True + if not fast: + iwconfig = wireless.GetIwconfig() + else: + iwconfig = '' + if check_for_wireless(iwconfig, wireless.GetWirelessIP(""), + self.set_status): + return True + else: + self.set_status(language['not_connected']) + return True + + + # Cheap little indicator stating that we are actually connecting + twirl = ['|','/','-','\\'] + def set_status(self,text,from_idle=False): + # Set the status text, usually called by the update_status method + # from_idle : a check to see if we are being called directly from the + # mainloop + # If we are being called as the result of trying to connect to + # something, and we aren't connecting to something, return False + # immediately. + if from_idle and not self.connecting: + return False + toAppend = '' + # If we are connecting and being called from the idle function, spin + # the wheel. + if from_idle and self.connecting: + # This is probably the wrong way to do this, but ir works for now. + toAppend=self.twirl[self.incr % 4] + self.footer2 = urwid.AttrWrap(urwid.Text(text+' '+toAppend),'important') + self.frame.set_footer(urwid.BoxAdapter( + urwid.ListBox([self.footer1,self.footer2]),2)) + return True + + # Make sure the screen is still working by providing a pretty counter. + # Not necessary in the end, but I will be using footer1 for stuff in + # the long run, so I might as well put something there. + incr = 0 + def idle_incr(self): + theText = "" + if self.connecting: + theText = "-- Connecting -- Press ESC to cancel" + self.footer1 = urwid.Text(str(self.incr) + ' '+theText) + self.incr+=1 + return True + + # Yeah, I'm copying code. Anything wrong with that? + #@wrap_exceptions() + def dbus_scan_finished(self): + # I'm pretty sure that I'll need this later. + #if not self.connecting: + #self.refresh_networks(fresh=False) + self.unlock_screen() + # I'm hoping that this will resolve Adam's problem with the screen lock + # remaining onscreen until a key is pressed. It goes away perfectly well + # here. + self.update_ui() + + # Same, same, same, same, same, same + #@wrap_exceptions() + def dbus_scan_started(self): + self.lock_screen() + + # Redraw the screen + @wrap_exceptions() + def update_ui(self): + #self.update_status() + canvas = self.frame.render( (self.size),True ) + ### GRRRRRRRRRRRRRRRRRRRRR ->^^^^ + # It looks like if I wanted to get the statusbar to update itself + # continuously, I would have to use overlay the canvasses and redirect + # the input. I'll try to get that working at a later time, if people + # want that "feature". + #canvaso = urwid.CanvasOverlay(self.dialog.render( (80,20),True),canvas,0,1) + ui.draw_screen((self.size),canvas) + keys = ui.get_input() + # Should make a keyhandler method, but this will do until I get around to + # that stage + if "f8" in keys or 'Q' in keys: + loop.quit() + return False + if "f5" in keys: + wireless.Scan() + if "enter" in keys: + # Should be a function of the labels, I think. + self.call_connect() + if "D" in keys: + # Disconnect from all networks. + daemon.Disconnect() + self.update_netlist() + if "esc" in keys: + # Force disconnect here if connection in progress + if self.connecting: + daemon.CancelConnect() + # Prevents automatic reconnecting if that option is enabled + daemon.SetForcedDisconnect(True) + if "P" in keys: + dialog = PrefsDialog(self.frame,(0,1),ui, + dbusmanager.get_dbus_ifaces()) + # There is some lag in using the buttons. Not my fault. + if dialog.run(ui,self.size,self.frame): + dialog.save_results() + self.update_ui() + if "A" in keys: + about_dialog(self.frame) + for k in keys: + if k == "window resize": + self.size = ui.get_cols_rows() + continue + self.frame.keypress( self.size, k ) + + if " " in keys: + #self.set_status('space pressed on wiredCB!') + wid,pos = self.wiredCB.get_body().get_selected() + text,attr = wid.get_text() + wired.ReadWiredNetworkProfile(text) + # Make sure our internal reference to the combobox matches the + # one found in the pile. + self.wiredCB = self.thePile.get_focus() + + return True + + # Bring back memories, anyone? + def call_connect(self): + wid = self.thePile.get_focus() + if wid is self.wiredCB: + #wid2,pos = self.wiredCB.get_focus() + # Apparently, connect() doesn't care about the networkid + self.connect(self,'wired',0) + #return "Wired network %i" % pos + elif wid is self.wlessLB: + #self.footer1 = urwid.Text("Wireless!") + wid2,pos = self.wlessLB.get_focus() + self.connect(self,'wireless',pos) + else: + self.set_status("call_connect() failed! This is definitely a bug!") + #return "Failure!" + + def connect(self, event, nettype, networkid): + """ Initiates the connection process in the daemon. """ + if nettype == "wireless": + # I need to do something that is similar to this in this UI, but + # I don't have an "advanced settings" dialog yet. + #if not self.check_encryption_valid(networkid, + # networkentry.advanced_dialog): + # self.edit_advanced(None, None, nettype, networkid, networkentry) + # return False + wireless.ConnectWireless(networkid) + elif nettype == "wired": + wired.ConnectWired() + self.update_status() + + +######################################## +##### INITIALIZATION FUNCTIONS +######################################## + +def main(): + global ui + + # We are _not_ python. + misc.RenameProcess('wicd-curses') + + ui = urwid.curses_display.Screen() + # Color scheme. + # Other potential color schemes can be found at: + # http://excess.org/urwid/wiki/RecommendedPalette + # Note: the current palette below is optimized for the linux console. + # For example, this looks particularly bad on a default-colored XTerm. + # NB: To find current terminal background use variable COLORFGBG + ui.register_palette([ + ('body','light gray','default'), + ('focus','dark magenta','light gray'), + ('header','light blue','default'), + ('important','light red','default'), + ('connected','dark green','default'), + ('connected focus','default','dark green'), + ('editcp', 'default', 'default', 'standout'), + ('editbx', 'light gray', 'dark blue'), + ('editfc', 'white','dark blue', 'bold'), + ('tab active','dark green','light gray'), + # Simple colors around text + ('green','dark green','default'), + ('blue','dark blue','default'), + ('red','dark red','default')]) + # This is a wrapper around a function that calls another a function that is a + # wrapper around a infinite loop. Fun. + ui.run_wrapper(run) + +def run(): + global loop,redraw_tag + + redraw_tag = -1 + app = appGUI() + + # Connect signals and whatnot to UI screen control functions + bus.add_signal_receiver(app.dbus_scan_finished, 'SendEndScanSignal', + 'org.wicd.daemon.wireless') + bus.add_signal_receiver(app.dbus_scan_started, 'SendStartScanSignal', + 'org.wicd.daemon.wireless') + # I've left this commented out many times. + bus.add_signal_receiver(app.update_netlist, 'StatusChanged', + 'org.wicd.daemon') + loop = gobject.MainLoop() + # Update what the interface looks like as an idle function + redraw_tag = gobject.idle_add(app.update_ui) + # Update the connection status on the bottom every 1.5 s. + gobject.timeout_add(1500,app.update_status) + gobject.idle_add(app.idle_incr) + # DEFUNCT: Terminate the loop if the UI is terminated. + #gobject.idle_add(app.stop_loop) + loop.run() + +# Mostly borrowed from gui.py +def setup_dbus(force=True): + global bus, daemon, wireless, wired, DBUS_AVAIL + try: + dbusmanager.connect_to_dbus() + except DBusException: + # I may need to be a little more verbose here. + # Suggestions as to what should go here + print "Can't connect to the daemon. Are you sure it is running?" + print "Please check the wicd log for error messages." + raise + # return False # <- Will need soon. + bus = dbusmanager.get_bus() + dbus_ifaces = dbusmanager.get_dbus_ifaces() + daemon = dbus_ifaces['daemon'] + wireless = dbus_ifaces['wireless'] + wired = dbus_ifaces['wired'] + DBUS_AVAIL = True + + return True + +setup_dbus() + +######################################## +##### MAIN ENTRY POINT +######################################## +if __name__ == '__main__': + main() + # Make sure that the terminal does not try to overwrite the last line of + # the program, so that everything looks pretty. + print ""