#!@PYTHON@ # -*-python-*- # This file is part of service-discovery-applet (sd-applet). # # sd-applet is free software; you can redistribute it and/or modify it # under the terms of the GNU Lesser General Public License as # published by the Free Software Foundation; either version 2 of the # License, or (at your option) any later version. # # sd-applet 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 Lesser General Public # License along with sd-applet; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 # USA. # # $id$ # # todo # * dict([el.split('=',1) for el in l ]) import os import sys import pygtk pygtk.require('2.0') def error_msg(msg): d = gtk.MessageDialog(parent=None, flags=gtk.DIALOG_MODAL, type=gtk.MESSAGE_ERROR, buttons=gtk.BUTTONS_OK) d.set_markup(msg) d.show_all() d.run() d.destroy() try: import avahi import dbus import gtk import gnomeapplet import gnome.ui import gconf except ImportError: error_msg("Sorry, to use this tool you need to install Avahi, pygtk and python-dbus.") try: import dbus.glib except ImportError, e: pass # Gconf Paths gc_options = "/apps/service-discovery-applet/options" gc_services = "/apps/service-discovery-applet/services" #from gettext import gettext as _ show_local_services = False show_notifications = False show_applet_name = False service_browsers = {} service_menu = gtk.Menu() zc_types = {} zc_services = {} zc_pretty_name = {'_ssh._tcp' : 'SSH Servers', '_http._tcp' : 'Web Servers', '_ftp._tcp' : 'Ftp Servers', '_workstation._tcp': 'Workstations' } menuZC = gtk.ImageMenuItem() menubar = gtk.MenuBar() def siocgifname(interface): global server if interface <= 0: return "any" else: return server.GetNetworkInterfaceNameByIndex(interface) def service_resolved(interface, protocol, name, type, domain, host, aprotocol, address, port, txt): print "Service data for service '%s' of type '%s' in domain '%s' on %s.%i:" % (name, type, domain, siocgifname(interface), protocol) print "\tHost %s (%s), port %i, TXT data: %s" % (host, address, port, avahi.txt_array_to_string_array(txt)) if os.path.exists("@scriptsdir@/%s.sh" % type): cmd = '@scriptsdir@/%s.sh "%s" %s %s %i "%s"' % (type, name, host, address, port," ".join(avahi.txt_array_to_string_array(txt))) os.system(cmd) # if type == "_http._tcp": # # url = "http://%s:%i" % (address,port) # gnome.url_show(url) # else: # os.system(cmd) def print_error(err): print "Error:", str(err) def menuitem_response(widget, interface, protocol, name, type, domain): server.ResolveService(interface, protocol, name, type, domain, avahi.PROTO_UNSPEC, reply_handler=service_resolved, error_handler=print_error) def new_service(interface, protocol, name, type, domain): global server, service_menu, zc_types, zc_pretty_name, zc_services, notif, show_notifications print "Found service '%s' of type '%s' in domain '%s' on %s.%i." % (name, type, domain, siocgifname(interface), protocol) if zc_types.has_key(type) == False: menuitem = gtk.ImageMenuItem() if zc_pretty_name.has_key(type): pretty_name = zc_pretty_name[type] else: pretty_name = type menuitem.add(gtk.Label(pretty_name)) img = gtk.Image() iconfile = "@iconsdir@/24x24/%s.png" % (type) if not os.path.exists(iconfile): iconfile = "@iconsdir@/24x24/service-discovery-applet.png" img.set_from_file(iconfile) menuitem.set_image(img) service_menu.add(menuitem) zc_types[type] = gtk.Menu() menuitem.set_submenu(zc_types[type]) menuitem.show_all() menuitem = gtk.MenuItem(name) zc_types[type].add(menuitem) zc_services[(interface, protocol, name, type, domain)] = menuitem menuitem.connect("activate", menuitem_response,interface, protocol, name, type, domain) menuitem.show_all() iconfile = "@iconsdir@/48x48/%s.png" % (type) if not os.path.exists(iconfile): iconfile = "@iconsdir@/48x48/service-discovery-applet.png" pretty_name = type if zc_pretty_name.has_key(type): pretty_name = zc_pretty_name[type] message = "Name : %s\nType : %s (%s)" % (name,pretty_name, type) try: if show_notifications == True: notif.Notify("Service Discovery Applet", iconfile, dbus.UInt32(0),"",dbus.Byte(0), "New Service found",message, [iconfile],[""],[""],True,dbus.UInt32(3)) except: print "can't use notification daemon" pass def remove_service(interface, protocol, name, type, domain): global zc_services, notif, show_notifications print "Service '%s' of type '%s' in domain '%s' on %s.%i disappeared." % (name, type, domain, siocgifname(interface), protocol) zc_types[type].remove(zc_services[(interface, protocol, name, type, domain)]) if zc_types[type].get_children() == []: service_menu.remove(zc_types[type].get_attach_widget()) del zc_types[type] iconfile = "@iconsdir@/48x48/%s.png" % (type) if not os.path.exists(iconfile): iconfile = "@iconsdir@/48x48/service-discovery-applet.png" pretty_name = type if zc_pretty_name.has_key(type): pretty_name = zc_pretty_name[type] message = "Name : %s\nType : %s (%s)" % (name, pretty_name, type) try: if show_notifications == True: notif.Notify("Service Discovery Applet", iconfile, dbus.UInt32(0),"",dbus.Byte(0), "Service disappeared",message, [iconfile],[""],[""],True,dbus.UInt32(3)) except: print "can't use notification daemon" pass def add_service_type(interface, protocol, type, domain): global server, service_browsers, system_bus # Are we already browsing this domain for this type? if service_browsers.has_key((interface, protocol, type, domain)): return print "Browsing for services of type '%s' in domain '%s' on %s.%i ..." % (type, domain, siocgifname(interface), protocol) b = dbus.Interface(system_bus.get_object(avahi.DBUS_NAME, server.ServiceBrowserNew(interface, protocol, type, domain)) , avahi.DBUS_INTERFACE_SERVICE_BROWSER) b.connect_to_signal('ItemNew', new_service) b.connect_to_signal('ItemRemove', remove_service) service_browsers[(interface, protocol, type, domain)] = b def del_service_type(interface, protocol, type, domain): service = (interface, protocol, type, domain) if not service_browsers.has_key(service): return sb = service_browsers[service] sb.Free() del service_browsers[service] # delete the sub menu of service_type if zc_types.has_key(type): service_menu.remove(zc_types[type].get_attach_widget()) del zc_types[type] # Callback: panel background changed def on_change_background(panelapplet, backgroundtype, color, pixmap): global menubar, menuZC panelapplet.modify_bg(gtk.STATE_NORMAL, color) menuZC.modify_bg(gtk.STATE_NORMAL, color) menubar.modify_bg(gtk.STATE_NORMAL, color) if backgroundtype == gnomeapplet.PIXMAP_BACKGROUND: print "PIXMAP_BACKGROUND" s1 = panelapplet.get_style() # s2 = menuZC.get_style() # s3 = menubar.get_style() s1.bg_pixmap[gtk.STATE_NORMAL] = pixmap # s2.bg_pixmap[gtk.STATE_NORMAL] = pixmap # s3.bg_pixmap[gtk.STATE_NORMAL] = pixmap if backgroundtype == gnomeapplet.COLOR_BACKGROUND: print "COLOR_BACKGROUND" if backgroundtype == gnomeapplet.NO_BACKGROUND: print "NO_BACKGROUND" def on_menubar_click(widget, event): # allow Middle- and Right-Mouse-Button to go through to the applet window if event.button != 1: widget.emit_stop_by_name("button-press-event") return False # This little hack is required to get Fitt's Law compliance - # i.e. to get the Menubar to be the full height of the panel. def on_menubar_size_allocate(menubar, rect): if (rect.x <= 0) or (rect.y <= 0): return False rect.x -= 1 rect.y -= 1 rect.width += 2 rect.height += 2 gtk.Widget.size_allocate(menubar, rect) return False def on_about(component, verb, applet): icon = gtk.Image() icon.set_from_file("@iconsdir@/48x48/service-discovery-applet.png") fullname = "Service Discovery Applet" copyright = "Copyright (C) 2005 Sebastien Estienne" description = "An applet to quickly access your zeroconf services." authors = ["Sebastien Estienne "] about = gnome.ui.About(fullname, "@version@", copyright, description, authors, None, None, icon.get_pixbuf()) about.set_icon(icon.get_pixbuf()) about.show() def on_config(component, verb, applet): os.system("service-discovery-config") #FIXME replace with gconf key def start_service_discovery(component, verb, applet): global system_bus, server, db , gc_client, domain, interface, protocol if len(domain) != 0: return try: domain = server.GetDomainName() except: print "Check that Avahi daemon is running!" return interface = avahi.IF_UNSPEC protocol = avahi.PROTO_UNSPEC gc_entries = gc_client.all_entries(gc_services) for gc_entry in gc_entries: if gc_client.get_bool(gc_entry.key) == True: service_type = os.path.basename(gc_entry.key) add_service_type(interface, protocol, service_type, domain) def stop_service_discovery(component, verb, applet): global domain if len(domain) == 0: return for service in service_browsers.copy(): del_service_type(service[0],service[1],service[2],service[3]) domain = "" # Callback called when a service is added/removed/enabled/disabled in gconf def gc_services_cb (client, cnxn_id, gc_entry, data): global interface, domain, protocol service_type = os.path.basename(gc_entry.key) # FIXME unset key if client.get_bool(gc_entry.key) == True: # Browse for a new service print "browse %s" % (service_type) add_service_type(interface, protocol, service_type, domain) else: # Stop browsing for a service print "remove %s" % (service_type) del_service_type(interface, protocol, service_type, domain) def gc_options_cb (client, cnxn_id, gc_entry, data): global show_notifications, show_applet_name, show_local_services key = os.path.basename(gc_entry.key) if key == "show_applet_name": show_applet_name = client.get_bool(gc_entry.key) if key == "show_notifications": show_notifications = client.get_bool(gc_entry.key) if key == "show_local_services": show_local_services = client.get_bool(gc_entry.key) def ServiceDiscoveryApplet_factory(applet, iid): global session_bus, notif, show_notifications, gc_client, server, system_bus, domain, menubar, menuZC # Gconf gc_client = gconf.client_get_default () gc_client.add_dir (gc_options, gconf.CLIENT_PRELOAD_NONE) show_local_services = gc_client.get_bool ("%s/%s" % (gc_options,"show_local_services")) show_notifications = gc_client.get_bool ("%s/%s" % (gc_options,"show_notifications")) show_applet_name = gc_client.get_bool ("%s/%s" % (gc_options,"show_applet_name")) gc_client.notify_add (gc_options, gc_options_cb, None) gc_client.add_dir (gc_services, gconf.CLIENT_PRELOAD_NONE) gc_client.notify_add (gc_services, gc_services_cb,None) # Applet MenuItem image = gtk.Image() image.set_from_file("@iconsdir@/24x24/service-discovery-applet.png") menuZC = gtk.ImageMenuItem() menuZC.add(gtk.Label('ZeroConf')) menuZC.set_image(image) menuZC.set_right_justified(True) menuZC.set_submenu(service_menu); menuZC.show_all() # Applet MenuBar gtk.rc_parse_string(''' style "service-discovery-applet-menubar-style" { GtkMenuBar::shadow-type = none GtkMenuBar::internal-padding = 0 } widget "*.service-discovery-applet" style "service-discovery-applet-menubar-style"''') menubar = gtk.MenuBar() menubar.set_name("service-discovery-applet") menubar.connect("button-press-event", on_menubar_click) menubar.connect("size-allocate", on_menubar_size_allocate) menubar.add(menuZC) #expand the applet with the panel applet.connect("change_background", on_change_background) applet.set_applet_flags(gnomeapplet.EXPAND_MINOR) #applet.add(menuZC) applet.add(menubar) applet.show_all() # funky right-click menu menuXml = """ """ applet.setup_menu(menuXml, [ ("SDA About", on_about), ("SDA Config", on_config), ("SDA Start", start_service_discovery), ("SDA Stop", stop_service_discovery) ], applet) popup = applet.get_popup_component() #Start Service Discovery domain = "" system_bus = dbus.SystemBus() server = dbus.Interface(system_bus.get_object(avahi.DBUS_NAME, avahi.DBUS_PATH_SERVER), avahi.DBUS_INTERFACE_SERVER) start_service_discovery(None, None, None) session_bus = dbus.SessionBus() obj = session_bus.get_object("org.freedesktop.Notifications", "/org/freedesktop/Notifications") notif = dbus.Interface(obj, "org.freedesktop.Notifications") return True print "Starting Service Discovery Applet" if __name__ == '__main__': if len(sys.argv) == 2 and sys.argv[1] == "-window": main_window = gtk.Window(gtk.WINDOW_TOPLEVEL) main_window.set_title("Service discovery applet") main_window.connect("destroy", gtk.main_quit) app = gnomeapplet.Applet() ServiceDiscoveryApplet_factory(app, None) app.reparent(main_window) main_window.show_all() gtk.main() sys.exit() else: gnomeapplet.bonobo_factory("OAFIID:GNOME_ServiceDiscoveryApplet_Factory", gnomeapplet.Applet.__gtype__, "Service discovery applet", "0", ServiceDiscoveryApplet_factory) print "Service Discovery Applet ended"