Compare with Previous | Blame | Download | View Log
#!/usr/bin/python# Copyright (C) 2008 Valmantas Paliksa <walmis at balticum-tv dot lt># Copyright (C) 2008 Tadas Dailyda <tadas at dailyda dot com>## Licensed under the GNU General Public License Version 3## 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 3 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, see <http://www.gnu.org/licenses/>.#import sysfrom subprocess import *import os.pathimport osimport pynotifyimport dbusimport dbus.glibimport gobjectimport gtkimport gtk.gdkimport __builtin__import traceback#support running uninstalled_dirname = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))if os.path.exists(os.path.join(_dirname,"ChangeLog")):sys.path.insert(0, _dirname)from blueman.Constants import *from blueman.Functions import *from blueman.main.applet.DbusService import DbusServicefrom blueman.main.Config import Configimport blueman.plugins.appletfrom blueman.plugins.AppletPlugin import AppletPluginimport blueman.bluez as Bluezfrom blueman.main.SignalTracker import SignalTrackerclass StopException(Exception):passclass LoadException(Exception):pass__builtin__.StopException = StopExceptionclass BluemanApplet(object):class Plugins(gobject.GObject):__gsignals__ = {'plugin-loaded' : (gobject.SIGNAL_NO_HOOKS, gobject.TYPE_NONE, (gobject.TYPE_STRING,)),'plugin-unloaded' : (gobject.SIGNAL_NO_HOOKS, gobject.TYPE_NONE, (gobject.TYPE_STRING,)),}def __init__(self, applet):gobject.GObject.__init__(self)self.__plugins = {}self.__classes = {}self.__deps = {}self.__cfls = {}self.__loaded = []self.applet = appletself.__config = Config()if self.__config.props.applet_plugins == None:self.__config.props.applet_plugins = []self.__config.connect('property-changed', self.on_property_changed)def on_property_changed(self, config, key, value):if key == "applet_plugins":if type(value) == list:for item in value:disable = item[0] == "!"if disable:item = item[1:]try:cls = self.__classes[item]if not cls.__unloadable__ and disable:print YELLOW("warning:"), item, "is not unloadable"elif item in self.__loaded and disable:self.Unload(item)elif item not in self.__loaded and not disable:self.Load(item)except KeyError:print YELLOW("warning:"), "Plugin %s not found" % itemcontinuedef GetClasses(self):return self.__classesdef GetLoaded(self):return self.__loadeddef GetDependencies(self):return self.__depsdef GetConflicts(self):return self.__cflsdef Load(self, name=None):if name:try:self.__load_plugin(self.__classes[name])except LoadException:passreturnpath = os.path.dirname(blueman.plugins.applet.__file__)plugins = []for root, dirs, files in os.walk(path):for f in files:if f.endswith(".py") and not (f.endswith(".pyc") or f.endswith("_.py")):plugins.append(f[0:-3])dprint(plugins)for plugin in plugins:try:__import__("blueman.plugins.applet.%s" % plugin, None, None, [])except ImportError, e:dprint("Unable to load plugin module %s\n%s" % (plugin, e))for cls in AppletPlugin.__subclasses__():self.__classes[cls.__name__] = clsif not cls.__name__ in self.__deps:self.__deps[cls.__name__] = []if not cls.__name__ in self.__cfls:self.__cfls[cls.__name__] = []for c in cls.__depends__:if not c in self.__deps:self.__deps[c] = []self.__deps[c].append(cls.__name__)for c in cls.__conflicts__:if not c in self.__cfls:self.__cfls[c] = []self.__cfls[c].append(cls.__name__)if c not in self.__cfls[cls.__name__]:self.__cfls[cls.__name__].append(c)c = self.__config.props.applet_pluginsfor name, cls in self.__classes.iteritems():for dep in self.__deps[name]:#plugins that are required by not unloadable plugins are not unloadable tooif not self.__classes[dep].__unloadable__:cls.__unloadable__ = Falseif (cls.__autoload__ or cls.__name__ in c) and not (cls.__unloadable__ and "!"+cls.__name__ in c):try:self.__load_plugin(cls)except LoadException:passdef Disabled(self, plugin):plugins = self.__config.props.applet_pluginsreturn "!"+plugin in pluginsdef Enabled(self, plugin):plugins = self.__config.props.applet_pluginsreturn plugin in pluginsdef __load_plugin(self, cls):if cls.__name__ in self.__loaded:returnfor dep in cls.__depends__:if not dep in self.__loaded:if not dep in self.__classes:raise "Could not satisfy dependency %s -> %s" % (cls.__name__, dep)try:self.__load_plugin(self.__classes[dep])except Exception, e:dprint(e)returnfor cfl in self.__cfls[cls.__name__]:if cfl in self.__classes:if self.__classes[cfl].__priority__ > cls.__priority__ and not self.Disabled(cfl) and not self.Enabled(cls.__name__):dprint("Not loading %s because it's conflict has higher priority" % cls.__name__)returnif cfl in self.__loaded:if cls.__priority__ > self.__classes[cfl].__priority__ and not self.Enabled(cfl):self.Unload(cfl)else:raise LoadException("Not loading conflicting plugin %s due to lower priority" % cls.__name__)dprint("loading", cls)inst = cls(self.applet)try:inst._load(self.applet)except Exception, e:dprint("Failed to load %s\n%s" % (cls.__name__, e))if not cls.__unloadable__:os._exit(1)else:self.__plugins[cls.__name__] = instself.__loaded.append(cls.__name__)self.emit("plugin-loaded", cls.__name__)def __getattr__(self, key):try:return self.__plugins[key]except:return self.__dict__[key]def Unload(self, name):if self.__classes[name].__unloadable__:for d in self.__deps[name]:self.Unload(d)if name in self.__loaded:dprint("Unloading %s" % name)try:inst = self.__plugins[name]inst._unload()except NotImplementedError:print "Plugin cannot be unloaded"else:self.__loaded.remove(name)del self.__plugins[name]self.emit("plugin-unloaded", name)else:raise Exception("Plugin %s is not unloadable" % name)def SetConfig(self, plugin, state):plugins = self.__config.props.applet_pluginsif plugin in plugins:plugins.remove(plugin)elif "!"+plugin in plugins:plugins.remove("!"+plugin)plugins.append("!"+plugin if not state else plugin)self.__config.props.applet_plugins = pluginsdef get_plugins(self):return self.__plugins#executes a function on all plugin instancesdef Run(self, function, *args, **kwargs):rets = []for inst in AppletPlugin.instances:try:ret = getattr(inst, function)(*args, **kwargs)rets.append(ret)except Exception, e:dprint("Function", function, "on", inst.__class__.__name__, "Failed")traceback.print_exc()return rets#executes a function on all plugin instances, runs a callback after each plugin returns somethingdef RunEx(self, function, callback, *args, **kwargs):for inst in AppletPlugin.instances:ret = getattr(inst, function)(*args, **kwargs)try:ret = callback(inst, ret)except StopException:returnexcept Exception, e:dprint("Function", function, "on", inst.__class__.__name__, "Failed")traceback.print_exc()returnif ret != None:args = retdef __init__(self):setup_icon_path()if not pynotify.init("Blueman"):dprint("Error: Failed to init pynotify")check_single_instance("blueman-applet")self.Manager = Noneself.DbusSvc = DbusService(self)self.Signals = SignalTracker()self.Plugins = BluemanApplet.Plugins(self)self.Plugins.Load()self.Plugins.Run("on_plugins_loaded")self.bus = dbus.SystemBus()self.bus.watch_name_owner("org.bluez", self.on_dbus_name_owner_change)self.bus.add_signal_receiver(self.on_adapter_property_changed, "PropertyChanged", "org.bluez.Adapter", "org.bluez", path_keyword="path")gtk.main()def manager_init(self):try:self.Signals.DisconnectAll()self.Manager = Bluez.Manager("gobject")self.Plugins.Run("on_manager_state_changed", True)self.Signals.Handle("bluez", self.Manager, self.on_adapter_removed, "AdapterRemoved")self.Signals.Handle("bluez", self.Manager, self.on_adapter_added, "AdapterAdded")except dbus.exceptions.DBusException, e:dprint(e)self.manager_deinit()dprint("Bluez DBus API not available. Listening for DBus name ownership changes")def manager_deinit(self):self.Signals.DisconnectAll()self.Manager = Noneself.Plugins.Run("on_manager_state_changed", False)def on_dbus_name_owner_change(self, owner):dprint("org.bluez owner changed to", owner)if owner == "":self.manager_deinit()elif self.Manager == None:self.manager_init()def on_adapter_property_changed(self, key, value, path):self.Plugins.Run("on_adapter_property_changed", path, key, value)def on_adapter_added(self, path):dprint("Adapter added ", path)def on_activate():dprint("Adapter activated")self.Plugins.Run("on_adapter_added", path)adapter = Bluez.Adapter(path)wait_for_adapter(adapter, on_activate)def on_adapter_removed(self, path):dprint("Adapter removed ", path)self.Plugins.Run("on_adapter_removed", path)BluemanApplet()