From 193aa246dd77d553a77052d8db168f8c65d1c246 Mon Sep 17 00:00:00 2001 From: Sebastien Estienne Date: Tue, 6 Sep 2005 16:09:43 +0000 Subject: * added a configuration ui * rewrote a lot things git-svn-id: file:///home/lennart/svn/public/service-discovery-applet/trunk@8 3be567f1-68ff-0310-b24a-ad7cc433fd2f --- src/Makefile.am | 21 ++- src/service-discovery-applet.in | 186 ++++++++++++------ src/service-discovery-config.glade | 373 +++++++++++++++++++++++++++++++++++++ src/service-discovery-config.in | 201 ++++++++++++++++++++ 4 files changed, 726 insertions(+), 55 deletions(-) create mode 100644 src/service-discovery-config.glade create mode 100755 src/service-discovery-config.in (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am index 8885425..01c41b7 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,8 +1,15 @@ +interfacesdir = $(INTERFACESDIR) + +interfaces_DATA = service-discovery-config.glade + pythonscripts = \ - service-discovery-applet + service-discovery-applet \ + service-discovery-config EXTRA_DIST = \ - service-discovery-applet.in + service-discovery-applet.in \ + service-discovery-config.in \ + $(interfaces_DATA) bin_SCRIPTS = $(pythonscripts) @@ -15,4 +22,14 @@ service-discovery-applet: service-discovery-applet.in $< > $@ chmod +x $@ +service-discovery-config: service-discovery-config.in + sed \ + -e 's,@PYTHON\@,$(PYTHON),g' \ + -e 's,@version\@,$(VERSION),g' \ + -e 's,@iconsdir\@,$(ICONSDIR),g' \ + -e 's,@interfacesdir\@,$(INTERFACESDIR),g' \ + -e 's,@scriptsdir\@,$(SCRIPTSDIR),g' \ + $< > $@ + chmod +x $@ + CLEANFILES = $(pythonscripts) diff --git a/src/service-discovery-applet.in b/src/service-discovery-applet.in index d773bfe..7a9845c 100755 --- a/src/service-discovery-applet.in +++ b/src/service-discovery-applet.in @@ -1,5 +1,5 @@ #!@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 @@ -20,7 +20,6 @@ # $id$ # # todo -# * memleaks ? # * dict([el.split('=',1) for el in l ]) import os @@ -43,12 +42,20 @@ import gtk import gnomeapplet import gnome import gnome.ui +import gconf + +# Gconf Paths +gc_options = "/apps/service-discovery-applet/options" +gc_services = "/apps/service-discovery-applet/services" + #from gettext import gettext as _ -domain = None +#type_browsed = ('_ssh._tcp', '_http._tcp','_ftp._tcp') -type_browsed = ('_ssh._tcp', '_http._tcp','_ftp._tcp') +show_local_services = False +show_notifications = False +show_applet_name = False service_browsers = {} service_menu = gtk.Menu() @@ -90,7 +97,7 @@ 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 + 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) @@ -119,17 +126,18 @@ def new_service(interface, protocol, name, type, domain): iconfile = "@iconsdir@/48x48/%s.png" % (type) message = "Name : %s\nType : %s (%s)" % (name,zc_pretty_name[type], type) try: - notif.Notify("Service Discovery Applet", - iconfile, dbus.UInt32(0),"",dbus.Byte(0), - "New Service found",message, - [iconfile],[""],[""],True,dbus.UInt32(3)) + 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 + 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) @@ -139,18 +147,20 @@ def remove_service(interface, protocol, name, type, domain): service_menu.remove(zc_types[type].get_attach_widget()) del zc_types[type] + # check that iconfil exist iconfile = "@iconsdir@/48x48/%s.png" % (type) message = "Name : %s\nType : %s (%s)" % (name,zc_pretty_name[type], type) try: - notif.Notify("Service Discovery Applet", - iconfile, dbus.UInt32(0),"",dbus.Byte(0), - "Service disappeared",message, - [iconfile],[""],[""],True,dbus.UInt32(3)) + 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 new_service_type(interface, protocol, type, domain): +def add_service_type(interface, protocol, type, domain): global server, service_browsers, system_bus # Are we already browsing this domain for this type? @@ -159,23 +169,26 @@ def new_service_type(interface, protocol, type, domain): 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 = 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 browse_domain(interface, protocol, domain): - global server +def del_service_type(interface, protocol, type, domain): - # Are we already browsing this domain? - for type in type_browsed: - new_service_type(interface, protocol, type, domain) - -def new_domain(interface, protocol, domain): - # We browse for .local anyway... - if domain != "local": - browse_domain(interface, protocol, 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] def on_menubar_click(widget, event): @@ -188,7 +201,7 @@ def on_menubar_click(widget, event): def on_about(component, verb, applet): icon = gtk.Image() - icon.set_from_file("@iconsdir@/service-discovery-applet.png") + icon.set_from_file("@iconsdir@/48x48/service-discovery-applet.png") fullname = "Service Discovery Applet" copyright = "Copyright (C) 2005 Sebastien Estienne" @@ -199,8 +212,85 @@ def on_about(component, verb, applet): 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) + print "start" + +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 = "" + print "stop" + +# 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 menuZC, system_bus, server, session_bus, domain, notif + global menuZC, session_bus, notif, show_notifications, gc_client, server, system_bus, domain + + # 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) print "Creating new applet instance" menubar = gtk.MenuBar() @@ -223,39 +313,29 @@ def ServiceDiscoveryApplet_factory(applet, iid): # funky right-click menu menuXml = """ - + + + """ - applet.setup_menu(menuXml, [("SDA About", on_about)], applet) - applet.setup_menu(menuXml, [("SDA Config", on_about)], applet) - + 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() +# popup.set_prop ("/button3/Service Discovery Applet Start Item", "_label", "prout") + + #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) - if domain is None: - # Explicitly browse .local - try: - browse_domain(avahi.IF_UNSPEC, avahi.PROTO_UNSPEC, "local") - except: - print "Can't connect to Avahi." - sys.exit(0) - - # Browse for other browsable domains - sdb = server.DomainBrowserNew(avahi.IF_UNSPEC, avahi.PROTO_UNSPEC, "", avahi.DOMAIN_BROWSER_BROWSE) - obj = system_bus.get_object(avahi.DBUS_NAME, sdb) - db = dbus.Interface(obj, avahi.DBUS_INTERFACE_DOMAIN_BROWSER) - db.connect_to_signal('ItemNew', new_domain) - - else: - # Just browse the domain the user wants us to browse - try: - browse_domain(avahi.IF_UNSPEC, avahi.PROTO_UNSPEC, domain) - except: - print "Can't connect to Avahi." - sys.exit(0) + start_service_discovery(None, None, None) session_bus = dbus.SessionBus() obj = session_bus.get_object("org.freedesktop.Notifications", "/org/freedesktop/Notifications") diff --git a/src/service-discovery-config.glade b/src/service-discovery-config.glade new file mode 100644 index 0000000..3724490 --- /dev/null +++ b/src/service-discovery-config.glade @@ -0,0 +1,373 @@ + + + + + + + 3 + True + Service Discovery Applet Preferences + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + True + False + True + False + False + GDK_WINDOW_TYPE_HINT_DIALOG + GDK_GRAVITY_NORTH_WEST + True + True + + + + + 350 + 450 + True + False + 0 + + + + True + GTK_BUTTONBOX_END + + + + True + True + gtk-close + True + GTK_RELIEF_NORMAL + True + 0 + + + + + + 0 + False + True + GTK_PACK_END + + + + + + True + True + True + True + GTK_POS_TOP + False + False + + + + 3 + True + False + 5 + + + + True + False + 0 + + + + True + 0.5 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + <b>Service type that will be browsed.</b> + False + True + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + True + True + + + + + 5 + False + False + + + + + + True + True + True + False + False + True + False + False + False + + + 0 + True + True + + + + + + services informations + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + True + + + + + + True + GTK_BUTTONBOX_DEFAULT_STYLE + 0 + + + + True + True + gtk-add + True + GTK_RELIEF_NORMAL + True + + + + + + True + True + gtk-remove + True + GTK_RELIEF_NORMAL + True + + + + + 0 + False + False + + + + + False + True + + + + + + True + Services + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + tab + + + + + + 5 + True + 4 + 2 + False + 5 + 5 + + + + True + True + Display notifications. + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 1 + 2 + 2 + 3 + fill + + + + + + True + Browse for my own services. + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 1 + 2 + 1 + 2 + fill + + + + + + True + <b>Advanced options :</b> + False + True + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 1 + 2 + 0 + 1 + fill + + + + + + + True + Display applet name in the panel. + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 1 + 2 + 3 + 4 + fill + + + + + False + True + + + + + + True + Advanced + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + tab + + + + + 0 + True + True + + + + + + + diff --git a/src/service-discovery-config.in b/src/service-discovery-config.in new file mode 100755 index 0000000..420ec7e --- /dev/null +++ b/src/service-discovery-config.in @@ -0,0 +1,201 @@ +#!@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$ +# + +import os +import avahi, gtk, gobject +import gconf + +from avahi.SimpleGladeApp import SimpleGladeApp + +( + COLUMN_ENABLED, + COLUMN_SERVICE, + COLUMN_NAME, + COLUMN_ACTION, + COLUMN_EDITABLE +) = range(5) + +glade_dir = "@interfacesdir@" + +gc_options = "/apps/service-discovery-applet/options" +gc_services = "/apps/service-discovery-applet/services" + +class Config_window(SimpleGladeApp): + def __init__(self, path="service-discovery-config.glade", root="sda-prefs-dialog", domain=None, **kwargs): + path = os.path.join(glade_dir, path) + SimpleGladeApp.__init__(self, path, root, domain, **kwargs) + + def __create_model(self): + lstore = gtk.ListStore( + gobject.TYPE_BOOLEAN, + gobject.TYPE_STRING, + gobject.TYPE_STRING, + gobject.TYPE_BOOLEAN, + gobject.TYPE_BOOLEAN) + + gc_entries = self.gc_client.all_entries(gc_services) + for gc_entry in gc_entries: + svc_enabled = self.gc_client.get_bool(gc_entry.key) + svc_type = os.path.basename(gc_entry.key) + + iter = lstore.append() + lstore.set(iter, + COLUMN_ENABLED, svc_enabled, + COLUMN_SERVICE, svc_type, + COLUMN_NAME, None, + COLUMN_ACTION, False, + COLUMN_EDITABLE, True) + return lstore + + def __add_columns(self, treeview): + model = treeview.get_model() + + # column for enabled toggles + renderer = gtk.CellRendererToggle() + renderer.connect('toggled', self.enabled_toggled, model) + + column = gtk.TreeViewColumn('Enabled', renderer, active=COLUMN_ENABLED) + + # set this column to a fixed sizing(of 50 pixels) + #column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED) + #column.set_fixed_width(50) + column.set_sort_column_id(COLUMN_ENABLED) + treeview.append_column(column) + + # column for service type + + renderer = gtk.CellRendererText() + renderer.connect("edited", self.on_cell_edited, model) + renderer.set_data("column", COLUMN_SERVICE) + + column = gtk.TreeViewColumn('Service type', renderer, + text=COLUMN_SERVICE, editable=COLUMN_EDITABLE) + treeview.append_column(column) + + # columns for service name +# column = gtk.TreeViewColumn('Service Name', gtk.CellRendererText(), +# text=COLUMN_NAME) +# column.set_sort_column_id(COLUMN_NAME) +# treeview.append_column(column) + + # column for action scripts +# renderer = gtk.CellRendererToggle() +# column = gtk.TreeViewColumn('Action', renderer, active=COLUMN_ACTION) +# column.set_sort_column_id(COLUMN_ACTION) +# treeview.append_column(column) + + def on_cell_edited(self, cell, path_string, service_type, model): + + iter = model.get_iter_from_string(path_string) + path = model.get_path(iter)[0] + column = cell.get_data("column") + + if column == COLUMN_SERVICE: + old_service_type = model.get_value(iter, column) + old_service_enabled= model.get_value(iter, COLUMN_ENABLED) + self.gc_client.unset("%s/%s" % (gc_services, old_service_type)) + model.set(iter, column, service_type) + self.gc_client.set_bool("%s/%s" % (gc_services, service_type), old_service_enabled) + + def on_add_service_clicked(self, button, model): + iter = model.append() + model.set (iter, + COLUMN_ENABLED, False, + COLUMN_SERVICE, "_service._protocol", + COLUMN_NAME, None, + COLUMN_ACTION, False, + COLUMN_EDITABLE, True) + + def on_del_service_clicked(self, button, treeview): + + selection = treeview.get_selection() + model, iter = selection.get_selected() + + if iter: + path = model.get_path(iter)[0] + service_type = model.get_value(iter,COLUMN_SERVICE) + self.gc_client.unset("%s/%s" % (gc_services, service_type)) + model.remove(iter) + #FIXME remove entry from gconf + + def enabled_toggled(self, cell, path, model): + # get toggled iter + iter = model.get_iter((int(path),)) + enabled = model.get_value(iter, COLUMN_ENABLED) + service_type = model.get_value(iter, COLUMN_SERVICE) + # do something with the value + enabled = not enabled + + # set new value + model.set(iter, COLUMN_ENABLED, enabled) + + self.gc_client.set_bool("%s/%s" % (gc_services, service_type), enabled) + + def cb_local_toggled(self,cb,client): + client.set_bool ("%s/%s" % (gc_options,"show_local_services"), cb.get_active()) + + def cb_notifications_toggled(self,cb,client): + client.set_bool ("%s/%s" % (gc_options,"show_notifications"), cb.get_active()) + + def cb_applet_name_toggled(self,cb,client): + client.set_bool ("%s/%s" % (gc_options,"show_applet_name"), cb.get_active()) + + def new(self): + print "A new main_window has been created" + + # Gconf + self.gc_client = gconf.client_get_default () + self.gc_client.add_dir (gc_options, gconf.CLIENT_PRELOAD_NONE) + + # images + self.image_services.set_from_file("@iconsdir@/48x48/service-discovery-applet.png") + + # connect advanced checkbuttons + self.checkbutton_local.set_active(self.gc_client.get_bool ("%s/%s" % (gc_options,"show_local_services"))) + self.checkbutton_local.connect('toggled',self.cb_local_toggled,self.gc_client) + + self.checkbutton_notifications.set_active(self.gc_client.get_bool ("%s/%s" % (gc_options,"show_notifications"))) + self.checkbutton_notifications.connect('toggled',self.cb_notifications_toggled,self.gc_client) + + self.checkbutton_applet_name.set_active(self.gc_client.get_bool ("%s/%s" % (gc_options,"show_applet_name"))) + self.checkbutton_applet_name.connect('toggled',self.cb_applet_name_toggled,self.gc_client) + + # The services treeview + model = self.__create_model() + + self.treeview_services.set_model(model) + self.__add_columns(self.treeview_services) + + # connect add/remove service buttons + self.button_add_service.connect("clicked", self.on_add_service_clicked, model) + self.button_del_service.connect("clicked", self.on_del_service_clicked, self.treeview_services) + + +def main(): + config_window = Config_window() + + config_window.run() + +if __name__ == "__main__": + main() + + -- cgit