diff options
Diffstat (limited to 'src/libs/xpcom18a4/python/components.py')
-rwxr-xr-x | src/libs/xpcom18a4/python/components.py | 244 |
1 files changed, 244 insertions, 0 deletions
diff --git a/src/libs/xpcom18a4/python/components.py b/src/libs/xpcom18a4/python/components.py new file mode 100755 index 00000000..9f450fe9 --- /dev/null +++ b/src/libs/xpcom18a4/python/components.py @@ -0,0 +1,244 @@ +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Python XPCOM language bindings. +# +# The Initial Developer of the Original Code is +# ActiveState Tool Corp. +# Portions created by the Initial Developer are Copyright (C) 2000, 2001 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Hammond <MarkH@ActiveState.com> (original author) +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# This module provides the JavaScript "components" interface +from . import xpt +import xpcom +import xpcom._xpcom as _xpcom +import xpcom.client +import xpcom.server + +StringTypes = [bytes, str] + +def _get_good_iid(iid): + if iid is None: + iid = _xpcom.IID_nsISupports + elif type(iid) in StringTypes and len(iid)>0 and iid[0] != "{": + iid = getattr(interfaces, iid) + return iid + +# The "manager" object. +manager = xpcom.client.Component(_xpcom.GetComponentManager(), _xpcom.IID_nsIComponentManager) + +# The component registrar +registrar = xpcom.client.Component(_xpcom.GetComponentManager(), _xpcom.IID_nsIComponentRegistrar) + +# The "interfaceInfoManager" object - JS doesnt have this. +interfaceInfoManager = _xpcom.XPTI_GetInterfaceInfoManager() + +# The serviceManager - JS doesnt have this either! +serviceManager = _xpcom.GetServiceManager() + +# The "Exception" object +Exception = xpcom.COMException + +# Base class for our collections. +# It appears that all objects supports "." and "[]" notation. +# eg, "interface.nsISupports" or interfaces["nsISupports"] +class _ComponentCollection: + # Bases are to over-ride 2 methods. + # _get_one(self, name) - to return one object by name + # _build_dict - to return a dictionary which provide access into + def __init__(self): + self._dict_data = None + def keys(self): + if self._dict_data is None: + self._dict_data = self._build_dict() + return list(self._dict_data.keys()) + def items(self): + if self._dict_data is None: + self._dict_data = self._build_dict() + return list(self._dict_data.items()) + def values(self): + if self._dict_data is None: + self._dict_data = self._build_dict() + return list(self._dict_data.values()) +# def has_key(self, key): +# if self._dict_data is None: +# self._dict_data = self._build_dict() +# return self._dict_data.has_key(key) + + def __len__(self): + if self._dict_data is None: + self._dict_data = self._build_dict() + return len(self._dict_data) + + def __getattr__(self, attr): + if self._dict_data is not None and attr in self._dict_data: + return self._dict_data[attr] + return self._get_one(attr) + def __getitem__(self, item): + if self._dict_data is not None and item in self._dict_data: + return self._dict_data[item] + return self._get_one(item) + +_constants_by_iid_map = {} + +class _Interface: + # An interface object. + def __init__(self, name, iid): + # Bypass self.__setattr__ when initializing attributes. + d = self.__dict__ + d['_iidobj_'] = iid # Allows the C++ framework to treat this as a native IID. + d['name'] = name + def __cmp__(self, other): + this_iid = self._iidobj_ + other_iid = getattr(other, "_iidobj_", other) + return cmp(this_iid, other_iid) + def __eq__(self, other): + this_iid = self._iidobj_ + other_iid = getattr(other, "_iidobj_", other) + return this_iid == other_iid + def __hash__(self): + return hash(self._iidobj_) + def __str__(self): + return str(self._iidobj_) + def __getitem__(self, item): + raise TypeError("components.interface objects are not subscriptable") + def __setitem__(self, item, value): + raise TypeError("components.interface objects are not subscriptable") + def __setattr__(self, attr, value): + raise AttributeError("Can not set attributes on components.Interface objects") + def __getattr__(self, attr): + # Support constants as attributes. + c = _constants_by_iid_map.get(self._iidobj_) + if c is None: + c = {} + i = xpt.Interface(self._iidobj_) + for c_ob in i.constants: + c[c_ob.name] = c_ob.value + _constants_by_iid_map[self._iidobj_] = c + if attr in c: + return c[attr] + raise AttributeError("'%s' interfaces do not define a constant '%s'" % (self.name, attr)) + + +class _Interfaces(_ComponentCollection): + def _get_one(self, name): + try: + item = interfaceInfoManager.GetInfoForName(name) + except xpcom.COMException as why: + # Present a better exception message, and give a more useful error code. + from . import nsError + raise xpcom.COMException(nsError.NS_ERROR_NO_INTERFACE, "The interface '%s' does not exist" % (name,)) + return _Interface(item.GetName(), item.GetIID()) + + def _build_dict(self): + ret = {} + enum = interfaceInfoManager.EnumerateInterfaces() + while not enum.IsDone(): + # Call the Python-specific FetchBlock, to keep the loop in C. + items = enum.FetchBlock(500, _xpcom.IID_nsIInterfaceInfo) + # This shouldnt be necessary, but appears to be so! + for item in items: + ret[item.GetName()] = _Interface(item.GetName(), item.GetIID()) + return ret + +# And the actual object people use. +interfaces = _Interfaces() + +del _Interfaces # Keep our namespace clean. + +################################################# +class _Class: + def __init__(self, contractid): + self.contractid = contractid + def __getattr__(self, attr): + if attr == "clsid": + rc = registrar.contractIDToCID(self.contractid) + # stash it away - it can never change! + self.clsid = rc + return rc + raise AttributeError("%s class has no attribute '%s'" % (self.contractid, attr)) + def createInstance(self, iid = None): + import xpcom.client + try: + return xpcom.client.Component(self.contractid, _get_good_iid(iid)) + except xpcom.COMException as details: + from . import nsError + # Handle "no such component" in a cleaner way for the user. + if details.errno == nsError.NS_ERROR_FACTORY_NOT_REGISTERED: + raise xpcom.COMException(details.errno, "No such component '%s'" % (self.contractid,)) + raise # Any other exception reraise. + def getService(self, iid = None): + return serviceManager.getServiceByContractID(self.contractid, _get_good_iid(iid)) + +class _Classes(_ComponentCollection): + def __init__(self): + _ComponentCollection.__init__(self) + def _get_one(self, name): + # XXX - Need to check the contractid is valid! + return _Class(name) + + def _build_dict(self): + ret = {} + enum = registrar.enumerateContractIDs() + while enum.hasMoreElements(): + # Call the Python-specific FetchBlock, to keep the loop in C. + items = enum.fetchBlock(2000, _xpcom.IID_nsISupportsCString) + for item in items: + name = str(item.data) + ret[name] = _Class(name) + return ret + +classes = _Classes() + +del _Classes + +del _ComponentCollection + +# The ID function +ID = _xpcom.ID + +# A helper to cleanup our namespace as xpcom shuts down. +class _ShutdownObserver: + _com_interfaces_ = interfaces.nsIObserver + def observe(self, service, topic, extra): + global manager, registrar, classes, interfaces, interfaceInfoManager, _shutdownObserver, serviceManager, _constants_by_iid_map + manager = registrar = classes = interfaces = interfaceInfoManager = _shutdownObserver = serviceManager = _constants_by_iid_map = None + xpcom.client._shutdown() + xpcom.server._shutdown() + +svc = _xpcom.GetServiceManager().getServiceByContractID("@mozilla.org/observer-service;1", interfaces.nsIObserverService) +# Observers will be QI'd for a weak-reference, so we must keep the +# observer alive ourself, and must keep the COM object alive, +# _not_ just the Python instance!!! +_shutdownObserver = xpcom.server.WrapObject(_ShutdownObserver(), interfaces.nsIObserver) +# Say we want a weak ref due to an assertion failing. If this is fixed, we can pass 0, +# and remove the lifetime hacks above! See http://bugzilla.mozilla.org/show_bug.cgi?id=99163 +svc.addObserver(_shutdownObserver, "xpcom-shutdown", 1) +del svc, _ShutdownObserver |