mirror of
https://github.com/gryf/wicd.git
synced 2025-12-20 04:48:00 +01:00
503 lines
19 KiB
Python
Executable File
503 lines
19 KiB
Python
Executable File
#!/usr/bin/env python
|
|
|
|
""" wicd - wireless connection daemon frontend implementation
|
|
|
|
This module implements a usermode frontend for wicd. It updates connection
|
|
information, provides an (optional) tray icon, and allows for launching of
|
|
the wicd GUI and Wired Profile Chooser.
|
|
|
|
class TrayIcon() -- Parent class of TrayIconGUI and IconConnectionInfo.
|
|
class TrayConnectionInfo() -- Child class of TrayIcon which provides
|
|
and updates connection status.
|
|
class TrayIconGUI() -- Child class of TrayIcon which implements the tray.
|
|
icon itself. Parent class of EdgyTrayIconGUI and DapperTrayIconGUI.
|
|
class EdgyTrayIconGUI() -- Implements the tray icon using a gtk.StatusIcon.
|
|
class DapperTrayIconGUI() -- Implements the tray icon using egg.trayicon.
|
|
def usage() -- Prints usage information.
|
|
def main() -- Runs the wicd frontend main loop.
|
|
|
|
"""
|
|
|
|
#
|
|
# Copyright (C) 2007 Adam Blackburn
|
|
# Copyright (C) 2007 Dan O'Reilly
|
|
#
|
|
# This program is free software; you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License Version 2 as
|
|
# published by the Free Software Foundation.
|
|
#
|
|
# 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, see <http://www.gnu.org/licenses/>.
|
|
#
|
|
|
|
import os
|
|
import sys
|
|
import gtk
|
|
import gobject
|
|
import dbus
|
|
import dbus.service
|
|
import locale
|
|
import gettext
|
|
import signal
|
|
import getopt
|
|
|
|
# Import egg.trayicon if we're using an older gtk version
|
|
if not (gtk.gtk_version[0] >= 2 and gtk.gtk_version[1] >= 10):
|
|
import egg.trayicon
|
|
USE_EGG = True
|
|
else:
|
|
USE_EGG = False
|
|
|
|
if getattr(dbus, 'version', (0, 0, 0)) >= (0, 41, 0):
|
|
import dbus.glib
|
|
|
|
# Wicd specific imports
|
|
import wpath
|
|
import misc
|
|
import gui
|
|
|
|
if sys.platform == 'linux2':
|
|
# Set process name. Only works on Linux >= 2.1.57.
|
|
try:
|
|
import dl
|
|
libc = dl.open('/lib/libc.so.6')
|
|
libc.call('prctl', 15, 'wicd\0', 0, 0, 0) # 15 is PR_SET_NAME
|
|
except:
|
|
pass
|
|
|
|
if __name__ == '__main__':
|
|
wpath.chdir(__file__)
|
|
|
|
log = misc.LogWriter()
|
|
bus = dbus.SystemBus()
|
|
|
|
# Connect to the daemon
|
|
try:
|
|
log.write('Attempting to connect daemon...')
|
|
proxy_obj = bus.get_object('org.wicd.daemon', '/org/wicd/daemon')
|
|
log.write('Success.')
|
|
except:
|
|
log.write('Daemon not running...')
|
|
misc.PromptToStartDaemon()
|
|
|
|
daemon = dbus.Interface(proxy_obj, 'org.wicd.daemon')
|
|
wireless = dbus.Interface(proxy_obj, 'org.wicd.daemon.wireless')
|
|
wired = dbus.Interface(proxy_obj, 'org.wicd.daemon.wired')
|
|
config = dbus.Interface(proxy_obj, 'org.wicd.daemon.config')
|
|
|
|
_ = misc.get_gettext()
|
|
language = {}
|
|
language['connected_to_wireless'] = _('Connected to $A at $B (IP: $C)')
|
|
language['connected_to_wired'] = _('Connected to wired network (IP: $A)')
|
|
language['not_connected'] = _('Not connected')
|
|
language['connecting'] = _('Connecting...')
|
|
|
|
class TrayIcon():
|
|
def __init__(self, use_tray):
|
|
if USE_EGG:
|
|
self.tr = self.DapperTrayIconGUI(use_tray)
|
|
else:
|
|
self.tr = self.EdgyTrayIconGUI(use_tray)
|
|
self.icon_info = self.TrayConnectionInfo(self.tr)
|
|
|
|
class TrayConnectionInfo():
|
|
''' class for updating the tray icon status '''
|
|
def __init__(self, tr):
|
|
''' initialize variables needed for the icon status methods '''
|
|
self.last_strength = -2
|
|
self.still_wired = False
|
|
self.network = ''
|
|
self.tried_reconnect = False
|
|
self.connection_lost_counter = 0
|
|
self.tr = tr
|
|
|
|
def wired_profile_chooser(self):
|
|
''' Launched the wired profile chooser '''
|
|
daemon.SetNeedWiredProfileChooser(False)
|
|
chooser = gui.WiredProfileChooser()
|
|
|
|
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.
|
|
|
|
'''
|
|
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
|
|
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, False otherwise.
|
|
|
|
'''
|
|
if wireless.GetWirelessIP() is None:
|
|
return False
|
|
|
|
# Reset this, just in case
|
|
self.tried_reconnect = False
|
|
|
|
# Try getting signal strength, default to 0 if something goes wrong.
|
|
try:
|
|
if daemon.GetSignalDisplayType() == 0:
|
|
wireless_signal = int(wireless.GetCurrentSignalStrength())
|
|
else:
|
|
wireless_signal = int(wireless.GetCurrentDBMStrength())
|
|
except:
|
|
wireless_signal = 0
|
|
|
|
if wireless_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 (wireless_signal != self.last_strength or
|
|
self.network != wireless.GetCurrentNetwork()):
|
|
self.last_strength = wireless_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.
|
|
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
|
|
self.network = str(wireless.GetCurrentNetwork())
|
|
daemon.SetCurrentInterface(daemon.GetWirelessInterface())
|
|
str_signal = daemon.FormatSignalForPrinting(str(wireless_signal))
|
|
self.tr.set_tooltip(language['connected_to_wireless']
|
|
.replace('$A', self.network)
|
|
.replace('$B', str_signal)
|
|
.replace('$C', str(wireless_ip)))
|
|
self.set_signal_image(wireless_signal, lock)
|
|
return True
|
|
|
|
def update_tray_icon(self):
|
|
''' Updates the tray icon and current connection status '''
|
|
|
|
# Disable logging if debugging isn't on to prevent log spam
|
|
if not daemon.GetDebugMode():
|
|
config.DisableLogging()
|
|
|
|
# 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
|
|
wireless_ip = wireless.GetWirelessIP()
|
|
wireless_found = self.check_for_wireless_connection(wireless_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()
|
|
|
|
return True
|
|
|
|
def set_signal_image(self, wireless_signal, lock):
|
|
''' Sets the tray icon picture 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:
|
|
self.tr.set_from_file(wpath.images + "bad-signal" + lock + ".png")
|
|
else:
|
|
self.tr.set_from_file(wpath.images + "no-signal.png")
|
|
return
|
|
elif daemon.GetSignalDisplayType() == 0:
|
|
if wireless_signal > 75:
|
|
self.tr.set_from_file(wpath.images + "high-signal" + lock + ".png")
|
|
elif wireless_signal > 50:
|
|
self.tr.set_from_file(wpath.images + "good-signal" + lock + ".png")
|
|
elif wireless_signal > 25:
|
|
self.tr.set_from_file(wpath.images + "low-signal" + lock + ".png")
|
|
elif wireless_signal > 0:
|
|
self.tr.set_from_file(wpath.images + "bad-signal" + lock + ".png")
|
|
else:
|
|
if wireless_signal >= -60:
|
|
self.tr.set_from_file(wpath.images + "high-signal" + lock + ".png")
|
|
elif wireless_signal >= -70:
|
|
self.tr.set_from_file(wpath.images + "good-signal" + lock + ".png")
|
|
elif wireless_signal >= -80:
|
|
self.tr.set_from_file(wpath.images + "low-signal" + lock + ".png")
|
|
else:
|
|
self.tr.set_from_file(wpath.images + "bad-signal" + lock + ".png")
|
|
# Since we have a signal, we should reset
|
|
# the connection loss counter.
|
|
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 = '''
|
|
<ui>
|
|
<menubar name="Menubar">
|
|
<menu action="Menu">
|
|
<menuitem action="Connect"/>
|
|
<separator/>
|
|
<menuitem action="About"/>
|
|
<menuitem action="Quit"/>
|
|
</menu>
|
|
</menubar>
|
|
</ui>
|
|
'''
|
|
actions = [
|
|
('Menu', None, 'Menu'),
|
|
('Connect', gtk.STOCK_CONNECT, '_Connect...', None,
|
|
'Connect to network', self.on_preferences),
|
|
('About', gtk.STOCK_ABOUT, '_About...', None,
|
|
'About wicd-tray-icon', self.on_about),
|
|
('Quit',gtk.STOCK_QUIT,'_Quit',None,'Quit wicd-tray-icon',
|
|
self.on_quit),
|
|
]
|
|
actg = gtk.ActionGroup('Actions')
|
|
actg.add_actions(actions)
|
|
self.manager = gtk.UIManager()
|
|
self.manager.insert_action_group(actg, 0)
|
|
self.manager.add_ui_from_string(menu)
|
|
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 '''
|
|
self.toggle_wicd_gui()
|
|
|
|
def on_quit(self, widget=None):
|
|
''' Closes the tray icon '''
|
|
sys.exit(0)
|
|
|
|
def on_preferences(self, data=None):
|
|
''' Opens the wicd GUI '''
|
|
self.toggle_wicd_gui()
|
|
|
|
def on_about(self, data = None):
|
|
''' Opens the About Dialog '''
|
|
dialog = gtk.AboutDialog()
|
|
dialog.set_name('wicd tray icon')
|
|
dialog.set_version('0.4')
|
|
dialog.set_comments('an icon that shows your network connectivity')
|
|
dialog.set_website('http://wicd.sourceforge.net')
|
|
dialog.run()
|
|
dialog.destroy()
|
|
|
|
def set_from_file(self, path = None):
|
|
''' 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 '''
|
|
if self.gui_win == None:
|
|
self.gui_win = gui.appGui()
|
|
elif self.gui_win.is_visible == False:
|
|
self.gui_win.show_win()
|
|
else:
|
|
self.gui_win.exit()
|
|
return True
|
|
|
|
|
|
class DapperTrayIconGUI(TrayIconGUI):
|
|
def __init__(self, use_tray=True):
|
|
''' initializes the tray icon '''
|
|
TrayIcon.TrayIconGUI.__init__(self)
|
|
self.use_tray = use_tray
|
|
if not use_tray:
|
|
self.toggle_wicd_gui()
|
|
return
|
|
|
|
self.tooltip = gtk.Tooltips()
|
|
self.eb = gtk.EventBox()
|
|
self.tray = egg.trayicon.TrayIcon("WicdTrayIcon")
|
|
self.pic = gtk.Image()
|
|
self.tooltip.set_tip(self.eb, "Initializing wicd...")
|
|
self.pic.set_from_file("images/no-signal.png")
|
|
|
|
self.eb.connect('button_press_event', self.tray_clicked)
|
|
self.eb.add(self.pic)
|
|
self.tray.add(self.eb)
|
|
self.tray.show_all()
|
|
|
|
def tray_clicked(self, widget, event):
|
|
''' 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 '''
|
|
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.
|
|
'''
|
|
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 '''
|
|
def __init__(self, use_tray=True):
|
|
TrayIcon.TrayIconGUI.__init__(self)
|
|
self.use_tray = use_tray
|
|
if not use_tray:
|
|
self.toggle_wicd_gui()
|
|
return
|
|
|
|
gtk.StatusIcon.__init__(self)
|
|
|
|
self.current_icon_path = ''
|
|
wireless.SetForcedDisconnect(False)
|
|
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_tooltip("Initializing wicd...")
|
|
|
|
def on_popup_menu(self, status, button, time):
|
|
''' 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 '''
|
|
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 usage():
|
|
print """
|
|
wicd 1.40
|
|
wireless (and wired) connection daemon front-end.
|
|
|
|
Arguments:
|
|
\t-n\t--no-tray\tRun wicd without the tray icon.
|
|
\t-h\t--help\t\tPrint this help.
|
|
"""
|
|
|
|
def main(argv):
|
|
""" The main frontend program.
|
|
|
|
Keyword arguments:
|
|
argv -- The arguments passed to the script.
|
|
|
|
"""
|
|
use_tray = True
|
|
|
|
try:
|
|
opts, args = getopt.getopt(sys.argv[1:], 'nh',
|
|
['help', 'no-tray'])
|
|
except getopt.GetoptError:
|
|
# Print help information and exit
|
|
usage()
|
|
sys.exit(2)
|
|
|
|
for o, a in opts:
|
|
if o in ('-h', '--help'):
|
|
usage()
|
|
sys.exit()
|
|
if o in ('-n', '--no-tray'):
|
|
use_tray = False
|
|
|
|
# Redirect stderr and stdout for logging purposes
|
|
#sys.stderr = log
|
|
#sys.stdout = log
|
|
|
|
# Set up the tray icon GUI and backend
|
|
tray_icon = TrayIcon(use_tray)
|
|
|
|
# Check to see if wired profile chooser was called before icon
|
|
# was launched (typically happens on startup or daemon restart)
|
|
if daemon.GetNeedWiredProfileChooser():
|
|
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)
|
|
|
|
# Enter the main loop
|
|
mainloop = gobject.MainLoop()
|
|
mainloop.run()
|
|
|
|
if __name__ == '__main__':
|
|
main(sys.argv)
|