Merge extensions/python/xpcom changes from DOM_AGNOSTIC2_BRANCH into the

trunk.


git-svn-id: svn://10.0.0.236/trunk@187878 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
mhammond%skippinet.com.au
2006-01-20 05:50:28 +00:00
parent 28dfbf4814
commit d394dc834d
56 changed files with 1710 additions and 958 deletions

View File

@@ -37,15 +37,18 @@
import os
import new
from xpcom import xpt, COMException, nsError
import logging
from xpcom import xpt, COMException, nsError, logger
# Suck in stuff from _xpcom we use regularly to prevent a module lookup
from xpcom._xpcom import IID_nsISupports, IID_nsIClassInfo, IID_nsISupportsCString, IID_nsISupportsWeakReference, \
IID_nsIWeakReference, XPTI_GetInterfaceInfoManager, GetComponentManager, XPTC_InvokeByIndex
from xpcom._xpcom import IID_nsISupports, IID_nsIClassInfo, \
IID_nsISupportsCString, IID_nsISupportsString, \
IID_nsISupportsWeakReference, IID_nsIWeakReference, \
XPTI_GetInterfaceInfoManager, GetComponentManager, XPTC_InvokeByIndex
# Attribute names we may be __getattr__'d for, but know we don't want to delegate
# Could maybe just look for startswith("__") but this may screw things for some objects.
_special_getattr_names = ["__del__", "__len__", "__nonzero__"]
_special_getattr_names = ["__del__", "__len__", "__nonzero__", "__eq__", "__neq__"]
_just_int_interfaces = ["nsISupportsPRInt32", "nsISupportsPRInt16", "nsISupportsPRUint32", "nsISupportsPRUint16", "nsISupportsPRUint8", "nsISupportsPRBool"]
_just_long_interfaces = ["nsISupportsPRInt64", "nsISupportsPRUint64"]
@@ -176,6 +179,21 @@ class _XPCOMBase:
def __hash__(self):
return hash(self._comobj_)
# The basic rich compare ops for equality
def __eq__(self, other):
try:
other = other._comobj_
except AttributeError:
pass
return self._comobj_ == other
def __neq__(self, other):
try:
other = other._comobj_
except AttributeError:
pass
return self._comobj_ != other
# See if the object support strings.
def __str__(self):
try:
@@ -184,6 +202,13 @@ class _XPCOMBase:
except COMException:
return self.__repr__()
def __unicode__(self):
try:
prin = self._comobj_.QueryInterface(IID_nsISupportsString)
except COMException:
return unicode(str(self))
return prin.data
# Try the numeric support.
def _do_conversion(self, interface_names, cvt):
iim = XPTI_GetInterfaceInfoManager()
@@ -206,7 +231,7 @@ class _XPCOMBase:
return self._do_conversion(_float_interfaces, float)
class Component(_XPCOMBase):
def __init__(self, ob, iid):
def __init__(self, ob, iid = IID_nsISupports):
assert not hasattr(ob, "_comobj_"), "Should be a raw nsIWhatever, not a wrapped one"
ob_name = None
if not hasattr(ob, "IID"):
@@ -220,7 +245,7 @@ class Component(_XPCOMBase):
self.__dict__['_interfaces_'] = {} # keyed by IID
self.__dict__['_interface_names_'] = {} # keyed by IID name
self.__dict__['_interface_infos_'] = {} # keyed by IID
self.__dict__['_name_to_interface_name_'] = {}
self.__dict__['_name_to_interface_iid_'] = {}
self.__dict__['_tried_classinfo_'] = 0
if ob_name is None:
@@ -256,10 +281,11 @@ class Component(_XPCOMBase):
for nominated_iid in interface_infos:
# Interface may appear twice in the class info list, so check this here.
if not self.__dict__['_interface_infos_'].has_key(nominated_iid):
self._remember_interface_info(nominated_iid)
# Just invoke our QI on the object
self.queryInterface(nominated_iid)
if real_cid is not None:
contractid_info = {}
contractid_info['_name_to_interface_name_'] = self.__dict__['_name_to_interface_name_']
contractid_info['_name_to_interface_iid_'] = self.__dict__['_name_to_interface_iid_']
contractid_info['_interface_infos_'] = self.__dict__['_interface_infos_']
contractid_info_cache[real_cid] = contractid_info
else:
@@ -269,26 +295,28 @@ class Component(_XPCOMBase):
self.__dict__['_com_classinfo_'] = classinfo
def _remember_interface_info(self, iid):
method_infos, getters, setters, constants = BuildInterfaceInfo(iid)
# Remember all the names so we can delegate
assert not self.__dict__['_interface_infos_'].has_key(iid), "Already remembered this interface!"
self.__dict__['_interface_infos_'][iid] = method_infos, getters, setters, constants
interface_name = iid.name
names = self.__dict__['_name_to_interface_name_']
for name in method_infos.keys(): names[name] = interface_name
for name in getters.keys(): names[name] = interface_name
for name in setters.keys(): names[name] = interface_name
for name in constants.keys(): names[name] = interface_name
# XXX - there is no good reason to cache this only in each instance
# It should be cached at the module level, so we don't need to
# rebuild the world for each new object.
iis = self.__dict__['_interface_infos_']
assert not iis.has_key(iid), "Already remembered this interface!"
try:
method_infos, getters, setters, constants = BuildInterfaceInfo(iid)
except COMException, why:
# Failing to build an interface info generally isn't a real
# problem - its probably just that the interface is non-scriptable.
logger.info("Failed to build interface info for %s: %s", iid, why)
# Remember the fact we failed.
iis[iid] = None
return
def _make_interface_info(self, ob, iid):
interface_infos = self._interface_infos_
assert not self._interfaces_.has_key(iid), "Already have made this interface"
method_infos, getters, setters, constants = interface_infos[iid]
new_interface = _Interface(ob, iid, method_infos, getters, setters, constants)
self._interfaces_[iid] = new_interface
self._interface_names_[iid.name] = new_interface
# No point remembering these.
del interface_infos[iid]
# Remember all the names so we can delegate
iis[iid] = method_infos, getters, setters, constants
names = self.__dict__['_name_to_interface_iid_']
for name in method_infos.keys(): names[name] = iid
for name in getters.keys(): names[name] = iid
for name in setters.keys(): names[name] = iid
for name in constants.keys(): names[name] = iid
def QueryInterface(self, iid):
if self._interfaces_.has_key(iid):
@@ -297,10 +325,24 @@ class Component(_XPCOMBase):
# Haven't seen this before - do a real QI.
if not self._interface_infos_.has_key(iid):
self._remember_interface_info(iid)
ret = self._comobj_.QueryInterface(iid, 0)
# print "Component QI for", iid, "yielded", ret
self._make_interface_info(ret, iid)
assert self._interfaces_.has_key(iid) and self._interface_names_.has_key(iid.name), "Making the interface didn't update the maps"
iface_info = self._interface_infos_[iid]
if iface_info is None:
# We have tried, but failed, to get this interface info. Its
# unlikely to work later either - its probably non-scriptable.
# That means our component wrappers are useless - so just return a
# raw nsISupports object with no wrapper.
return self._comobj_.QueryInterface(iid, 0)
raw_iface = self._comobj_.QueryInterface(iid, 0)
method_infos, getters, setters, constants = iface_info
new_interface = _Interface(raw_iface, iid, method_infos,
getters, setters, constants)
self._interfaces_[iid] = new_interface
self._interface_names_[iid.name] = new_interface
# As we 'flatten' objects when possible, a QI on an object just
# returns ourself - all the methods etc on this interface are
# available.
return self
queryInterface = QueryInterface # Alternate name.
@@ -312,47 +354,51 @@ class Component(_XPCOMBase):
interface = self.__dict__['_interface_names_'].get(attr, None)
if interface is not None:
return interface
interface_name = self.__dict__['_name_to_interface_name_'].get(attr, None)
# See if we know the IID of an interface providing this attribute
iid = self.__dict__['_name_to_interface_iid_'].get(attr, None)
# This may be first time trying this interface - get the nsIClassInfo
if interface_name is None and not self._tried_classinfo_:
if iid is None and not self._tried_classinfo_:
self._build_all_supported_interfaces_()
interface_name = self.__dict__['_name_to_interface_name_'].get(attr, None)
if interface_name is not None:
interface = self.__dict__['_interface_names_'].get(interface_name, None)
iid = self.__dict__['_name_to_interface_iid_'].get(attr, None)
# If the request is for an interface name, it may now be
# available.
interface = self.__dict__['_interface_names_'].get(attr, None)
if interface is not None:
return interface
if iid is not None:
interface = self.__dict__['_interfaces_'].get(iid, None)
if interface is None:
iid = XPTI_GetInterfaceInfoManager().GetInfoForName(interface_name).GetIID()
self.QueryInterface(iid)
interface = self.__dict__['_interface_names_'][interface_name]
interface = self.__dict__['_interfaces_'][iid]
return getattr(interface, attr)
# Some interfaces may provide this name via "native" support.
# Loop over all interfaces, and if found, cache it for next time.
for interface in self.__dict__['_interfaces_'].values():
try:
ret = getattr(interface, attr)
self.__dict__['_name_to_interface_name_'][attr] = interface._iid_.name
self.__dict__['_name_to_interface_iid_'][attr] = interface._iid_
return ret
except AttributeError:
pass
raise AttributeError, "XPCOM component '%s' has no attribute '%s'" % (self._object_name_, attr)
def __setattr__(self, attr, val):
interface_name = self._name_to_interface_name_.get(attr, None)
iid = self._name_to_interface_iid_.get(attr, None)
# This may be first time trying this interface - get the nsIClassInfo
if interface_name is None and not self._tried_classinfo_:
if iid is None and not self._tried_classinfo_:
self._build_all_supported_interfaces_()
interface_name = self.__dict__['_name_to_interface_name_'].get(attr, None)
if interface_name is not None:
interface = self._interface_names_.get(interface_name, None)
iid = self.__dict__['_name_to_interface_iid_'].get(attr, None)
if iid is not None:
interface = self._interfaces_.get(iid, None)
if interface is None:
iid = XPTI_GetInterfaceInfoManager().GetInfoForName(interface_name).GetIID()
self.QueryInterface(iid)
interface = self.__dict__['_interface_names_'][interface_name]
interface = self.__dict__['_interfaces_'][iid]
setattr(interface, attr, val)
return
raise AttributeError, "XPCOM component '%s' has no attribute '%s'" % (self._object_name_, attr)
def __repr__(self):
# We can advantage from nsIClassInfo - use it.
def _get_classinfo_repr_(self):
try:
if not self._tried_classinfo_:
self._build_all_supported_interfaces_()
@@ -362,13 +408,21 @@ class Component(_XPCOMBase):
# we are flagged as *not* having built, so the error is seen
# by the first caller who actually *needs* this to work.
self.__dict__['_tried_classinfo_'] = 0
infos = self.__dict__['_interface_infos_']
if infos:
iface_names = ",".join([iid.name for iid in infos.keys()])
iface_desc = " (implementing %s)" % (iface_names,)
else:
iface_desc = " (with no class info)"
return "<XPCOM component '%s'%s>" % (self._object_name_,iface_desc)
iface_names = self.__dict__['_interface_names_'].keys()
try:
iface_names.remove("nsISupports")
except ValueError:
pass
iface_names.sort()
iface_desc = "implementing %s" % (",".join(iface_names),)
return iface_desc
def __repr__(self):
# We can advantage from nsIClassInfo - use it.
iface_desc = self._get_classinfo_repr_()
return "<XPCOM component '%s' (%s)>" % (self._object_name_,iface_desc)
class _Interface(_XPCOMBase):
def __init__(self, comobj, iid, method_infos, getters, setters, constants):
@@ -403,7 +457,7 @@ class _Interface(_XPCOMBase):
if len(param_infos)!=1: # Only expecting a retval
raise RuntimeError, "Can't get properties with this many args!"
args = ( param_infos, () )
return XPTC_InvokeByIndex(self, method_index, args)
return XPTC_InvokeByIndex(self._comobj_, method_index, args)
# See if we have a method info waiting to be turned into a method.
# Do this last as it is a one-off hit.
@@ -431,7 +485,7 @@ class _Interface(_XPCOMBase):
if len(param_infos)!=1: # Only expecting a single input val
raise RuntimeError, "Can't set properties with this many args!"
real_param_infos = ( param_infos, (val,) )
return XPTC_InvokeByIndex(self, method_index, real_param_infos)
return XPTC_InvokeByIndex(self._comobj_, method_index, real_param_infos)
def __repr__(self):
return "<XPCOM interface '%s'>" % (self._object_name_,)
@@ -453,7 +507,7 @@ class WeakReference:
>>> some_ob = components.classes['...']
>>> weak_ref = WeakReference(some_ob)
>>> new_ob = weak_ref() # new_ob is effectively "some_ob" at this point
>>> # EXCEPT: new_ob may be None of some_ob has already died - a
>>> # EXCEPT: new_ob may be None if some_ob has already died - a
>>> # weak reference does not keep the object alive (that is the point)
You should never hold onto this resulting strong object for a long time,