From 031bf2a05ca9b5070333a3717df458f7bc5d2a84 Mon Sep 17 00:00:00 2001 From: "markh%activestate.com" Date: Sun, 27 May 2001 02:51:18 +0000 Subject: [PATCH] Add interface flattening to Python XPCOM bindings. Not part of the build, but a=drivers@mozilla.org anyway! git-svn-id: svn://10.0.0.236/trunk@95969 18797224-902f-48f8-a5cc-f745e15eee43 --- .../python/xpcom/client/__init__.py | 289 +++++++++++++----- mozilla/extensions/python/xpcom/components.py | 3 +- .../extensions/python/xpcom/doc/tutorial.html | 16 +- .../python/xpcom/makefile.stupid.linux | 1 + mozilla/extensions/python/xpcom/readme.html | 9 +- .../python/xpcom/server/__init__.py | 4 +- .../extensions/python/xpcom/server/policy.py | 85 ++++-- .../extensions/python/xpcom/src/PyGBase.cpp | 2 +- .../python/xpcom/src/PyIClassInfo.cpp | 159 ++++++++++ .../python/xpcom/src/PyIComponentManager.cpp | 2 +- .../python/xpcom/src/PyIInterfaceInfo.cpp | 2 +- .../python/xpcom/src/PyISupports.cpp | 21 +- mozilla/extensions/python/xpcom/src/PyXPCOM.h | 93 +++++- .../extensions/python/xpcom/src/PyXPCOM_std.h | 19 +- .../python/xpcom/src/TypeObject.cpp | 11 +- .../python/xpcom/src/loader/pyloader.cpp | 3 + .../extensions/python/xpcom/src/makefile.win | 2 + mozilla/extensions/python/xpcom/src/xpcom.cpp | 79 ++--- .../python/xpcom/test/output/test_misc | 9 +- .../python/xpcom/test/test_components.py | 4 +- .../xpcom/test/test_isupports_primitives.py | 2 +- .../extensions/python/xpcom/test/test_misc.py | 20 +- .../python/xpcom/test/test_test_component.py | 12 +- mozilla/extensions/python/xpcom/xpt.py | 1 + 24 files changed, 649 insertions(+), 199 deletions(-) create mode 100644 mozilla/extensions/python/xpcom/src/PyIClassInfo.cpp diff --git a/mozilla/extensions/python/xpcom/client/__init__.py b/mozilla/extensions/python/xpcom/client/__init__.py index b54d5c7eb7b..2787910e137 100644 --- a/mozilla/extensions/python/xpcom/client/__init__.py +++ b/mozilla/extensions/python/xpcom/client/__init__.py @@ -17,9 +17,11 @@ import os import new -from xpcom import xpt, _xpcom, COMException, nsError +from xpcom import xpt, COMException, nsError -XPTC_InvokeByIndex = _xpcom.XPTC_InvokeByIndex +# Suck in stuff from _xpcom we use regularly to prevent a module lookup +from xpcom._xpcom import IID_nsISupports, IID_nsIClassInfo, IID_nsISupportsString, IID_nsISupportsWeakReference, \ + IID_nsIWeakReference, XPTI_GetInterfaceInfoManager, NS_GetGlobalComponentManager, XPTC_InvokeByIndex _just_int_interfaces = ["nsISupportsPRInt32", "nsISupportsPRInt16", "nsISupportsPRUint32", "nsISupportsPRUint16", "nsISupportsPRUint8", "nsISupportsPRBool"] _just_long_interfaces = ["nsISupportsPRInt64", "nsISupportsPRUint64"] @@ -31,9 +33,7 @@ _float_interfaces = _just_float_interfaces + _just_long_interfaces + _just_int_i method_template = """ def %s(self, %s): - return XPTC_InvokeByIndex(self._comobj_, %d, - (%s, - (%s))) + return XPTC_InvokeByIndex(self._comobj_, %d, (%s, (%s))) """ def _MakeMethodCode(method): # Build a declaration @@ -66,8 +66,43 @@ def _MakeMethodCode(method): # Keyed by IID, each item is a tuple of (methods, getters, setters) interface_cache = {} +# Keyed by [iid][name], each item is an unbound method. +interface_method_cache = {} -# Fully process the interface - generate method code, etc. +def _shutdown(): + interface_cache.clear() + interface_method_cache.clear() + +# Fully process the named method, generating method code etc. +def BuildMethod(method_info, iid): + name = method_info.name + try: + return interface_method_cache[iid][name] + except KeyError: + pass + # Generate it. + assert not (method_info.IsSetter() or method_info.IsGetter()), "getters and setters should have been weeded out by now" + method_code = _MakeMethodCode(method_info) + # Build the method - We only build a function object here + # - they are bound to each instance as needed. + +## print "Method Code for %s (%s):" % (name, iid) +## print method_code + codeObject = compile(method_code, "" % (name,), "exec") + # Exec the code object + tempNameSpace = {} + exec codeObject in globals(), tempNameSpace + ret = tempNameSpace[name] + if not interface_method_cache.has_key(iid): + interface_method_cache[iid] = {} + interface_method_cache[iid][name] = ret + return ret + +from xpcom.xpcom_consts import XPT_MD_GETTER, XPT_MD_SETTER, XPT_MD_NOTXPCOM, XPT_MD_CTOR, XPT_MD_HIDDEN +FLAGS_TO_IGNORE = XPT_MD_NOTXPCOM | XPT_MD_CTOR | XPT_MD_HIDDEN + +# Pre-process the interface - generate a list of methods, constants etc, +# but don't actually generate the method code. def BuildInterfaceInfo(iid): ret = interface_cache.get(iid, None) if ret is None: @@ -75,72 +110,30 @@ def BuildInterfaceInfo(iid): method_code_blocks = [] getters = {} setters = {} - method_names = [] + method_infos = {} interface = xpt.Interface(iid) for m in interface.methods: - if not m.IsNotXPCOM() and \ - not m.IsHidden() and \ - not m.IsConstructor(): - # Yay - a method we can use! - if m.IsSetter(): + flags = m.flags + if flags & FLAGS_TO_IGNORE == 0: + if flags & XPT_MD_SETTER: param_flags = map(lambda x: (x.param_flags,) + xpt.MakeReprForInvoke(x), m.params) setters[m.name] = m.method_index, param_flags - elif m.IsGetter(): + elif flags & XPT_MD_GETTER: param_flags = map(lambda x: (x.param_flags,) + xpt.MakeReprForInvoke(x), m.params) getters[m.name] = m.method_index, param_flags else: - method_names.append(m.name) - method_code_blocks.append(_MakeMethodCode(m)) + method_infos[m.name] = m # Build the constants. constants = {} for c in interface.constants: constants[c.name] = c.value - # Build the methods - We only build function objects here - # - they are bound to each instance at instance creation. - methods = {} - if len(method_code_blocks)!=0: - method_code = "\n".join(method_code_blocks) -## print "Method Code:" -## print method_code - codeObject = compile(method_code, "","exec") - # Exec the code object - tempNameSpace = {} - exec codeObject in globals(), tempNameSpace # self.__dict__, self.__dict__ - for name in method_names: - methods[name] = tempNameSpace[name] - ret = methods, getters, setters, constants + ret = method_infos, getters, setters, constants interface_cache[iid] = ret return ret -def Component(ob, iid): - ob_name = None - if not hasattr(ob, "IID"): - ob_name = ob - cm = _xpcom.NS_GetGlobalComponentManager() - ob = cm.CreateInstanceByContractID(ob) - return Interface(ob, iid) - -class Interface: - """Implements a dynamic interface using xpcom reflection. - """ - def __init__(self, ob, iid, object_name = None): - ob = ob.QueryInterface(iid, 0) # zero means "no auto-wrap" - self.__dict__['_comobj_'] = ob - # Hack - the last interface only! - methods, getters, setters, constants = BuildInterfaceInfo(iid) - self.__dict__['_interface_infos_'] = getters, setters - self.__dict__['_interface_methods_'] = methods # Unbound methods. - - self.__dict__.update(constants) - # We remember the constant names to prevent the user trying to assign to them! - self.__dict__['_constant_names_'] = constants.keys() - - if object_name is None: - object_name = "object with interface '%s'" % (iid.name,) - self.__dict__['_object_name_'] = object_name - +class _XPCOMBase: def __cmp__(self, other): try: other = other._comobj_ @@ -152,19 +145,19 @@ class Interface: return hash(self._comobj_) def __repr__(self): - return "" % (self._comobj_.IID.name,) + return "" % (self._object_name_,) # See if the object support strings. def __str__(self): try: - self._comobj_.QueryInterface(_xpcom.IID_nsISupportsString) + self._comobj_.QueryInterface(IID_nsISupportsString, 0) return str(self._comobj_) except COMException: return self.__repr__() # Try the numeric support. def _do_conversion(self, interface_names, cvt): - iim = _xpcom.XPTI_GetInterfaceInfoManager() + iim = XPTI_GetInterfaceInfoManager() for interface_name in interface_names: iid = iim.GetInfoForName(interface_name).GetIID() try: @@ -182,6 +175,139 @@ class Interface: def __float__(self): return self._do_conversion(_float_interfaces, float) + +class Component(_XPCOMBase): + def __init__(self, ob, iid): + assert not hasattr(ob, "_comobj_"), "Should be a raw nsIWhatever, not a wrapped one" + ob_name = None + if not hasattr(ob, "IID"): + ob_name = ob + cm = NS_GetGlobalComponentManager() + ob = cm.CreateInstanceByContractID(ob) + assert not hasattr(ob, "_comobj_"), "The created object should be a raw nsIWhatever, not a wrapped one" + # Keep a reference to the object in the component too + self.__dict__['_comobj_'] = ob + # hit __dict__ directly to avoid __setattr__() + 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__['_tried_classinfo_'] = 0 + + if ob_name is None: + ob_name = "" + self.__dict__['_object_name_'] = ob_name + self.QueryInterface(iid) + + def _build_all_supported_interfaces_(self): + # Use nsIClassInfo, but don't do it at object construction to keep perf up. + # Only pay the penalty when we really need it. + assert not self._tried_classinfo_, "already tried to get the class info." + self.__dict__['_tried_classinfo_'] = 1 + # See if nsIClassInfo is supported. + try: + classinfo = self._comobj_.QueryInterface(IID_nsIClassInfo, 0) + except COMException: + classinfo = None + if classinfo is not None: +# print "YAY - have class info!!", classinfo + real_cid = classinfo.contractID + if real_cid is not None: + self.__dict__['_object_name_'] = real_cid + for nominated_iid in classinfo.getInterfaces(): + self._remember_interface_info(nominated_iid) + 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 + + 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] + + def QueryInterface(self, iid): + if self._interfaces_.has_key(iid): + assert self._interface_names_.has_key(iid.name), "_interfaces_ has the key, but _interface_names_ does not!" + return self + # 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" + return self + + queryInterface = QueryInterface # Alternate name. + + def __getattr__(self, attr): + # First allow the interface name to return the "raw" interface + 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) + # This may be first time trying this interface - get the nsIClassInfo + if interface_name 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) + if interface is None: + iid = XPTI_GetInterfaceInfoManager().GetInfoForName(interface_name).GetIID() + self.QueryInterface(iid) + interface = self.__dict__['_interface_names_'][interface_name] + 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 + 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) + # This may be first time trying this interface - get the nsIClassInfo + if interface_name 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_[interface_name] + setattr(interface, attr, val) + return + raise AttributeError, "XPCOM component '%s' can not set attribute '%s'" % (self._object_name_, attr) + +class _Interface(_XPCOMBase): + def __init__(self, comobj, iid, method_infos, getters, setters, constants): + self.__dict__['_comobj_'] = comobj + self.__dict__['_iid_'] = iid + self.__dict__['_property_getters_'] = getters + self.__dict__['_property_setters_'] = setters + self.__dict__['_method_infos_'] = method_infos # method infos waiting to be turned into real methods. + self.__dict__['_methods_'] = {} # unbound methods + self.__dict__['_object_name_'] = iid.name + self.__dict__.update(constants) + # We remember the constant names to prevent the user trying to assign to them! + self.__dict__['_constant_names_'] = constants.keys() def __getattr__(self, attr): # Allow the underlying interface to provide a better implementation if desired. @@ -189,19 +315,29 @@ class Interface: if ret is not None: return ret # Do the function thing first. - unbound_method = self.__dict__['_interface_methods_'].get(attr) + unbound_method = self.__dict__['_methods_'].get(attr, None) if unbound_method is not None: return new.instancemethod(unbound_method, self, self.__class__) - getters, setters = self.__dict__['_interface_infos_'] + getters = self.__dict__['_property_getters_'] info = getters.get(attr) - if info is None: - raise AttributeError, "XPCOM component '%s' has no attribute '%s'" % (self._object_name_, attr) - method_index, param_infos = info - 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._comobj_, method_index, args) + if info is not None: + method_index, param_infos = info + 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) + + # See if we have a method info waiting to be turned into a method. + # Do this last as it is a one-off hit. + method_info = self.__dict__['_method_infos_'].get(attr, None) + if method_info is not None: + unbound_method = BuildMethod(method_info, self._iid_) + # Cache it locally + self.__dict__['_methods_'][attr] = unbound_method + return new.instancemethod(unbound_method, self, self.__class__) + + raise AttributeError, "XPCOM component '%s' has no attribute '%s'" % (self._object_name_, attr) def __setattr__(self, attr, val): # If we already have a __dict__ item of that name, and its not one of @@ -210,7 +346,7 @@ class Interface: self.__dict__[attr] = val return # Start sniffing for what sort of attribute this might be? - getters, setters = self.__dict__['_interface_infos_'] + setters = self.__dict__['_property_setters_'] info = setters.get(attr) if info is None: raise AttributeError, "XPCOM component '%s' can not set attribute '%s'" % (self._object_name_, attr) @@ -218,12 +354,13 @@ class Interface: 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._comobj_, method_index, real_param_infos) + return XPTC_InvokeByIndex(self, method_index, real_param_infos) + # Called by the _xpcom C++ framework to wrap interfaces up just # before they are returned. def MakeInterfaceResult(ob, iid): - return Interface(ob, iid) + return Component(ob, iid) class WeakReference: """A weak-reference object. You construct a weak reference by passing @@ -233,7 +370,7 @@ class WeakReference: Once you have a weak-reference, you can "call" the object to get back a strong reference. Eg: - >>> some_ob = components.classes['...] + >>> 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 @@ -243,18 +380,18 @@ class WeakReference: or else you defeat the purpose of the weak-reference. """ def __init__(self, ob, iid = None): - swr = Interface(ob, _xpcom.IID_nsISupportsWeakReference) - self._comobj_ = Interface(swr.GetWeakReference(), _xpcom.IID_nsIWeakReference) + swr = Component(ob._comobj_, IID_nsISupportsWeakReference) + self._comobj_ = Component(swr.GetWeakReference()._comobj_, IID_nsIWeakReference) if iid is None: try: iid = ob.IID except AttributeError: - iid = _xpcom.IID_nsISupports + iid = IID_nsISupports self._iid_ = iid def __call__(self, iid = None): if iid is None: iid = self._iid_ try: - return Interface(self._comobj_.QueryReferent(iid), iid) + return Component(self._comobj_.QueryReferent(iid)._comobj_, iid) except COMException, details: if details.errno != nsError.NS_ERROR_NULL_POINTER: raise diff --git a/mozilla/extensions/python/xpcom/components.py b/mozilla/extensions/python/xpcom/components.py index 4e7318bf63f..16a82e5076b 100644 --- a/mozilla/extensions/python/xpcom/components.py +++ b/mozilla/extensions/python/xpcom/components.py @@ -32,7 +32,7 @@ def _get_good_iid(iid): return iid # The "manager" object. -manager = xpcom.client.Interface(_xpcom.NS_GetGlobalComponentManager(), _xpcom.IID_nsIComponentManager) +manager = xpcom.client.Component(_xpcom.NS_GetGlobalComponentManager(), _xpcom.IID_nsIComponentManager) # The "interfaceInfoManager" object - JS doesnt have this. interfaceInfoManager = _xpcom.XPTI_GetInterfaceInfoManager() @@ -190,6 +190,7 @@ class _ShutdownObserver: global interfaceInfoManager global _shutdownObserver manager = interfaceInfoManager = _shutdownObserver = None + xpcom.client._shutdown() svc = _xpcom.GetGlobalServiceManager().GetService("@mozilla.org/observer-service;1", interfaces.nsIObserverService) # Observers will be QI'd for a weak-reference, so we must keep the diff --git a/mozilla/extensions/python/xpcom/doc/tutorial.html b/mozilla/extensions/python/xpcom/doc/tutorial.html index 6fac965b4e6..78deac85ce8 100644 --- a/mozilla/extensions/python/xpcom/doc/tutorial.html +++ b/mozilla/extensions/python/xpcom/doc/tutorial.html @@ -74,7 +74,7 @@ and implements the nsISample interface.

Thus, a complete Python program that uses this component is shown below.

from xpcom import components
 cls = components.classes["@mozilla.org/sample;1"]
-ob = cls.createInstance(components.interfaces.nsISample)
+ob = cls.createInstance() # no need to specify an IID for most components
 # nsISample defines a "value" property - let's use it!
 ob.value = "new value"
 if ob.value != "new value":
@@ -233,6 +233,20 @@ any given XPCOM method, there is only one possible type for a given parameter.
 
 
+

Interface Flattening

+

Most people can ignore this information - Python XPCOM objects just +work.  However, if you are familiar with xpcom from C++ and the concept of QueryInterface, +you may like to read this.

+

Most components support the concept of "interface +flattening".  Such objects can report the interfaces they support, +allowing languages such as Python and Javascript avoid using QueryInterface.  +When you are using an XPCOM object from Python, you can just call methods and +reference properties without regard for the interface that implements it.

+

When multiple interfaces share the same method or property name, you can use +the name of the interface as a differentiator.  Thus, ob.nsIFoo.close() +will call close on ob's nsIFoo interface, while ob.nsIBar.close() +will use the nsIBar interface.  ob.close() is not defined.

+ diff --git a/mozilla/extensions/python/xpcom/makefile.stupid.linux b/mozilla/extensions/python/xpcom/makefile.stupid.linux index 040fb320b3e..f9bdf72841c 100644 --- a/mozilla/extensions/python/xpcom/makefile.stupid.linux +++ b/mozilla/extensions/python/xpcom/makefile.stupid.linux @@ -117,6 +117,7 @@ XPCOM_SRC_OBJECTS = \ src/PyGStub.o \ src/PyGInputStream.o \ src/PyGWeakReference.o \ + src/PyIClassInfo.o \ src/PyIComponentManager.o \ src/PyIInputStream.o \ src/PyIEnumerator.o \ diff --git a/mozilla/extensions/python/xpcom/readme.html b/mozilla/extensions/python/xpcom/readme.html index 11b947b96fc..abb2a445af2 100644 --- a/mozilla/extensions/python/xpcom/readme.html +++ b/mozilla/extensions/python/xpcom/readme.html @@ -14,7 +14,7 @@

Python XPCOM Package

-

Mozilla CVS Version - Last updated April 2001

+

Mozilla CVS Version - Last updated May 2001

This is the readme for the Python interface to XPCOM.

XPCOM is an acronym for "Cross Platform COM".  It has come out of the Mozilla project, which @@ -37,7 +37,7 @@ is, then none of this probably interests you at all!

Note: This package requires Python 1.6 or later; we recommend using the latest -official Python version (currently 2.0).  This package works +official Python version (currently 2.1).  This package works very well with the latest ActivePython, and does not require any external modules or packages beyond what is provided in the core Python release for each platform.

@@ -86,6 +86,11 @@ documented here just in case!
  • Changes to allow building with stand-alone XPCOM.
  • +

    Version 0.92 - May 2001

    +

    Implement interface flattening.  You should (almost) never need to use QueryInterface()!  +We are still 100% backwards compatible, so usage of QI still works - just is +generally not necessary.

    + diff --git a/mozilla/extensions/python/xpcom/server/__init__.py b/mozilla/extensions/python/xpcom/server/__init__.py index c075675726f..4ac7cb5a2df 100644 --- a/mozilla/extensions/python/xpcom/server/__init__.py +++ b/mozilla/extensions/python/xpcom/server/__init__.py @@ -29,7 +29,7 @@ from xpcom import _xpcom tracer = None # Wrap an instance in an interface (via a policy) -def WrapObject(ob, iid, policy = None): +def WrapObject(ob, iid, policy = None, bWrapClient = 1): """Called by the framework to attempt to wrap an object in a policy. If iid is None, it will use the first interface the object indicates it supports. @@ -38,7 +38,7 @@ def WrapObject(ob, iid, policy = None): policy = DefaultPolicy if tracer is not None: ob = tracer(ob) - return _xpcom.WrapObject(policy( ob, iid ), iid) + return _xpcom.WrapObject(policy( ob, iid ), iid, bWrapClient) # Create the main module for the Python loader. # This is a once only init process, and the returned object diff --git a/mozilla/extensions/python/xpcom/server/policy.py b/mozilla/extensions/python/xpcom/server/policy.py index 9478a9c0ff4..d041849f738 100644 --- a/mozilla/extensions/python/xpcom/server/policy.py +++ b/mozilla/extensions/python/xpcom/server/policy.py @@ -20,33 +20,67 @@ import xpcom import traceback import xpcom.server import operator +import types + +IID_nsISupports = _xpcom.IID_nsISupports +XPT_MD_IS_GETTER = xpcom_consts.XPT_MD_IS_GETTER +XPT_MD_IS_SETTER = xpcom_consts.XPT_MD_IS_SETTER _supports_primitives_map_ = {} # Filled on first use. +_interface_sequence_types_ = types.TupleType, types.ListType +_string_types_ = types.StringType, types.UnicodeType +XPTI_GetInterfaceInfoManager = _xpcom.XPTI_GetInterfaceInfoManager + def _GetNominatedInterfaces(obj): ret = getattr(obj, "_com_interfaces_", None) if ret is None: return None # See if the user only gave one. - try: - ret[0] - except TypeError: + if type(ret) not in _interface_sequence_types_: ret = [ret] real_ret = [] # For each interface, walk to the root of the interface tree. - iim = _xpcom.XPTI_GetInterfaceInfoManager() + iim = XPTI_GetInterfaceInfoManager() for interface in ret: - try: + # Allow interface name or IID. + interface_info = None + if type(interface) in _string_types_: + try: + interface_info = iim.GetInfoForName(interface) + except COMException: + pass + if interface_info is None: + # Allow a real IID interface_info = iim.GetInfoForIID(interface) - except COMException: - # Allow an interface name. - interface_info = iim.GetInfoForName(interface) real_ret.append(interface_info.GetIID()) parent = interface_info.GetParent() while parent is not None: - real_ret.append(parent.GetIID()) + parent_iid = parent.GetIID() + if parent_iid == IID_nsISupports: + break + real_ret.append(parent_iid) parent = parent.GetParent() return real_ret +class DefaultClassInfo: + _com_interfaces_ = _xpcom.IID_nsIClassInfo + def __init__(self, klass): + self.klass = klass + self.contractID = getattr(klass, "_reg_contractid_", None) + self.classDescription = getattr(klass, "_reg_desc_", None) + self.classID = getattr(klass, "_reg_clsid_", None) + self.implementationLanguage = 3 # Python - avoid lookups just for this + self.flags = 0 # what to do here?? + self.interfaces = None + + def getInterfaces(self): + if self.interfaces is None: + self.interfaces = _GetNominatedInterfaces(self.klass) + return self.interfaces + + def getHelperForLanguage(self, language): + return None # Not sure what to do here. + class DefaultPolicy: def __init__(self, instance, iid): self._obj_ = instance @@ -54,16 +88,15 @@ class DefaultPolicy: self._iid_ = iid if ni is None: raise ValueError, "The object '%r' can not be used as a COM object" % (instance,) - if iid not in ni: - # The object may delegate QI. - try: - delegate_qi = instance._query_interface_ - except AttributeError: - delegate_qi = None - # Perform the actual QI and throw away the result - the _real_ - # QI performed by the framework will set things right! - if delegate_qi is None or not delegate_qi(iid): - raise ServerException(nsError.NS_ERROR_NO_INTERFACE) + # This is really only a check for the user + if __debug__: + if iid != IID_nsISupports and iid not in ni: + # The object may delegate QI. + delegate_qi = getattr(instance, "_query_interface_", None) + # Perform the actual QI and throw away the result - the _real_ + # QI performed by the framework will set things right! + if delegate_qi is None or not delegate_qi(iid): + raise ServerException(nsError.NS_ERROR_NO_INTERFACE) # Stuff for the magic interface conversion. self._interface_info_ = None self._interface_iid_map_ = {} # Cache - Indexed by (method_index, param_index) @@ -80,7 +113,11 @@ class DefaultPolicy: # NOTE: We could have simply returned the instance and let the framework # do the auto-wrap for us - but this way we prevent a round-trip back into Python # code just for the autowrap. - return xpcom.server.WrapObject(self._obj_, iid) + return xpcom.server.WrapObject(self._obj_, iid, bWrapClient = 0) + + # Always support nsIClassInfo + if iid == _xpcom.IID_nsIClassInfo: + return xpcom.server.WrapObject(DefaultClassInfo(self._obj_.__class__), iid, bWrapClient = 0) # See if the instance has a QI # use lower-case "_query_interface_" as win32com does, and it doesnt really matter. @@ -100,7 +137,7 @@ class DefaultPolicy: _supports_primitives_map_[special_iid] = (attr, cvt) attr, cvt = _supports_primitives_map_.get(iid, (None,None)) if attr is not None and hasattr(self._obj_, attr): - return xpcom.server.WrapObject(SupportsPrimitive(iid, self._obj_, attr, cvt), iid) + return xpcom.server.WrapObject(SupportsPrimitive(iid, self._obj_, attr, cvt), iid, bWrapClient = 0) # Out of clever things to try! return None # We dont support this IID. @@ -117,13 +154,13 @@ class DefaultPolicy: iid = self._interface_info_.GetIIDForParam(method_index, param_index) self._interface_iid_map_[(method_index, param_index)] = iid # iid = _xpcom.IID_nsISupports - return client.Interface(interface, iid) + return client.Component(interface, iid) def _CallMethod_(self, com_object, index, info, params): # print "_CallMethod_", index, info, params flags, name, param_descs, ret = info assert ret[1][0] == xpcom_consts.TD_UINT32, "Expected an nsresult (%s)" % (ret,) - if xpcom_consts.XPT_MD_IS_GETTER(flags): + if XPT_MD_IS_GETTER(flags): # Look for a function of that name func = getattr(self._obj_, "get_" + name, None) if func is None: @@ -132,7 +169,7 @@ class DefaultPolicy: else: ret = func(*params) return 0, ret - elif xpcom_consts.XPT_MD_IS_SETTER(flags): + elif XPT_MD_IS_SETTER(flags): # Look for a function of that name func = getattr(self._obj_, "set_" + name, None) if func is None: diff --git a/mozilla/extensions/python/xpcom/src/PyGBase.cpp b/mozilla/extensions/python/xpcom/src/PyGBase.cpp index cfea27907a3..5a4c3ceaace 100644 --- a/mozilla/extensions/python/xpcom/src/PyGBase.cpp +++ b/mozilla/extensions/python/xpcom/src/PyGBase.cpp @@ -171,7 +171,7 @@ PyG_Base::AutoWrapPythonInstance(PyObject *ob, const nsIID &iid, nsISupports **p obIID = Py_nsIID::PyObjectFromIID(iid); if (obIID==NULL) goto done; - args = Py_BuildValue("OO", ob, obIID); + args = Py_BuildValue("OOzi", ob, obIID, NULL, 0); if (args==NULL) goto done; wrap_ret = PyEval_CallObject(func, args); if (wrap_ret==NULL) goto done; diff --git a/mozilla/extensions/python/xpcom/src/PyIClassInfo.cpp b/mozilla/extensions/python/xpcom/src/PyIClassInfo.cpp new file mode 100644 index 00000000000..58be94ec982 --- /dev/null +++ b/mozilla/extensions/python/xpcom/src/PyIClassInfo.cpp @@ -0,0 +1,159 @@ +/* + * 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 ActiveState Tool Corp. are Copyright (C) 2001 + * ActiveState Tool Corp. All Rights Reserved. + * + * Contributor(s): Mark Hammond (original author) + * + */ + +// +// This code is part of the XPCOM extensions for Python. +// +// Written May 2001 by Mark Hammond. +// +// Based heavily on the Python COM support, which is +// (c) Mark Hammond and Greg Stein. +// +// (c) 2001, ActiveState corp. + +#include "PyXPCOM_std.h" +#include "nsIClassInfo.h" + +static nsIClassInfo *_GetI(PyObject *self) { + nsIID iid = NS_GET_IID(nsIClassInfo); + + if (!Py_nsISupports::Check(self, iid)) { + PyErr_SetString(PyExc_TypeError, "This object is not the correct interface"); + return NULL; + } + return (nsIClassInfo *)Py_nsISupports::GetI(self); +} + +static PyObject *PyGetInterfaces(PyObject *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, "")) + return NULL; + nsIClassInfo *pI = _GetI(self); + if (pI==NULL) + return NULL; + + nsIID** iidArray = nsnull; + PRUint32 iidCount = 0; + nsresult r; + Py_BEGIN_ALLOW_THREADS; + r = pI->GetInterfaces(&iidCount, &iidArray); + Py_END_ALLOW_THREADS; + if ( NS_FAILED(r) ) + return PyXPCOM_BuildPyException(r); + + PyObject *ret = PyTuple_New(iidCount); + if (ret==NULL) + return NULL; + for (PRUint32 i=0;iGetHelperForLanguage(language, &pi); + Py_END_ALLOW_THREADS; + if ( NS_FAILED(r) ) + return PyXPCOM_BuildPyException(r); + + return Py_nsISupports::PyObjectFromInterface(pi, NS_GET_IID(nsISupports), PR_FALSE); +} + +static PyObject *MakeStringOrNone(char *v) +{ + if (v) + return PyString_FromString(v); + Py_INCREF(Py_None); + return Py_None; +} + +#define GETATTR_CHECK_RESULT(nr) if (NS_FAILED(nr)) return PyXPCOM_BuildPyException(nr) + +PyObject * +Py_nsIClassInfo::getattr(const char *name) +{ + nsIClassInfo *pI = _GetI(this); + if (pI==NULL) + return NULL; + + nsresult nr; + PyObject *ret = NULL; + if (strcmp(name, "contractID")==0) { + char *str_ret; + Py_BEGIN_ALLOW_THREADS; + nr = pI->GetContractID(&str_ret); + Py_END_ALLOW_THREADS; + GETATTR_CHECK_RESULT(nr); + ret = MakeStringOrNone(str_ret); + nsAllocator::Free(str_ret); + } else if (strcmp(name, "classDescription")==0) { + char *str_ret; + Py_BEGIN_ALLOW_THREADS; + nr = pI->GetClassDescription(&str_ret); + Py_END_ALLOW_THREADS; + GETATTR_CHECK_RESULT(nr); + ret = MakeStringOrNone(str_ret); + nsAllocator::Free(str_ret); + } else if (strcmp(name, "classID")==0) { + nsIID *iid; + Py_BEGIN_ALLOW_THREADS; + nr = pI->GetClassID(&iid); + Py_END_ALLOW_THREADS; + GETATTR_CHECK_RESULT(nr); + ret = Py_nsIID::PyObjectFromIID(*iid); + nsAllocator::Free(iid); + } else if (strcmp(name, "implementationLanguage")==0) { + PRUint32 i; + Py_BEGIN_ALLOW_THREADS; + nr = pI->GetImplementationLanguage(&i); + Py_END_ALLOW_THREADS; + GETATTR_CHECK_RESULT(nr); + ret = PyInt_FromLong(i); + } else { + ret = Py_nsISupports::getattr(name); + } + return ret; +} + +int +Py_nsIClassInfo::setattr(const char *name, PyObject *v) +{ + return Py_nsISupports::setattr(name, v); + +} + +struct PyMethodDef +PyMethods_IClassInfo[] = +{ + { "getInterfaces", PyGetInterfaces, 1}, + { "GetInterfaces", PyGetInterfaces, 1}, + { "getHelperForLanguage", PyGetHelperForLanguage, 1}, + { "GetHelperForLanguage", PyGetHelperForLanguage, 1}, + {NULL} +}; diff --git a/mozilla/extensions/python/xpcom/src/PyIComponentManager.cpp b/mozilla/extensions/python/xpcom/src/PyIComponentManager.cpp index 022ca8605fb..134c7748c53 100644 --- a/mozilla/extensions/python/xpcom/src/PyIComponentManager.cpp +++ b/mozilla/extensions/python/xpcom/src/PyIComponentManager.cpp @@ -70,7 +70,7 @@ static PyObject *PyCreateInstanceByContractID(PyObject *self, PyObject *args) return PyXPCOM_BuildPyException(r); /* Return a type based on the IID (with no extra ref) */ - return Py_nsISupports::PyObjectFromInterface(pis, iid, PR_FALSE); + return Py_nsISupports::PyObjectFromInterface(pis, iid, PR_FALSE, PR_FALSE); } static PyObject *PyContractIDToClassID(PyObject *self, PyObject *args) diff --git a/mozilla/extensions/python/xpcom/src/PyIInterfaceInfo.cpp b/mozilla/extensions/python/xpcom/src/PyIInterfaceInfo.cpp index 2a71f8bc0ec..22a0d789210 100644 --- a/mozilla/extensions/python/xpcom/src/PyIInterfaceInfo.cpp +++ b/mozilla/extensions/python/xpcom/src/PyIInterfaceInfo.cpp @@ -117,7 +117,7 @@ static PyObject *PyGetParent(PyObject *self, PyObject *args) Py_END_ALLOW_THREADS; if ( NS_FAILED(r) ) return PyXPCOM_BuildPyException(r); - return Py_nsISupports::PyObjectFromInterface(pRet, NS_GET_IID(nsIInterfaceInfo), PR_FALSE); + return Py_nsISupports::PyObjectFromInterface(pRet, NS_GET_IID(nsIInterfaceInfo), PR_FALSE, PR_FALSE); } static PyObject *PyGetMethodCount(PyObject *self, PyObject *args) diff --git a/mozilla/extensions/python/xpcom/src/PyISupports.cpp b/mozilla/extensions/python/xpcom/src/PyISupports.cpp index 9029d12712f..f227d582d57 100644 --- a/mozilla/extensions/python/xpcom/src/PyISupports.cpp +++ b/mozilla/extensions/python/xpcom/src/PyISupports.cpp @@ -93,6 +93,25 @@ Py_nsISupports::SafeRelease(Py_nsISupports *ob) } } +/* virtual */ PyObject * +Py_nsISupports::getattr(const char *name) +{ + if (strcmp(name, "IID")==0) + return Py_nsIID::PyObjectFromIID( m_iid ); + + PyXPCOM_TypeObject *this_type = (PyXPCOM_TypeObject *)ob_type; + return Py_FindMethodInChain(&this_type->chain, this, (char *)name); +} + +/* virtual */ int +Py_nsISupports::setattr(const char *name, PyObject *v) +{ + char buf[128]; + sprintf(buf, "%s has read-only attributes", ob_type->tp_name ); + PyErr_SetString(PyExc_TypeError, buf); + return -1; +} + /*static*/ Py_nsISupports * Py_nsISupports::Constructor(nsISupports *pInitObj, const nsIID &iid) { @@ -287,7 +306,7 @@ Py_nsISupports::MakeInterfaceResult(PyObject *pyis, done: if (PyErr_Occurred()) { NS_ABORT_IF_FALSE(ret==NULL, "Have an error, but also a return val!"); - PyXPCOM_LogError("Creating an interface object to be used as a parameter failed\n"); + PyXPCOM_LogError("Creating an interface object to be used as a result failed\n"); PyErr_Clear(); } Py_XDECREF(mod); diff --git a/mozilla/extensions/python/xpcom/src/PyXPCOM.h b/mozilla/extensions/python/xpcom/src/PyXPCOM.h index dc2786c55e8..4987d0b3f1f 100644 --- a/mozilla/extensions/python/xpcom/src/PyXPCOM.h +++ b/mozilla/extensions/python/xpcom/src/PyXPCOM.h @@ -206,7 +206,9 @@ public: static void RegisterInterface( const nsIID &iid, PyTypeObject *t); static void InitType(); - ~Py_nsISupports(); + virtual ~Py_nsISupports(); + virtual PyObject *getattr(const char *name); + virtual int setattr(const char *name, PyObject *val); protected: // ctor is protected - must create objects via // PyObjectFromInterface() @@ -398,7 +400,7 @@ protected: private: }; -// For the Gateways me manually implement. +// For the Gateways we manually implement. #define PYGATEWAY_BASE_SUPPORT(INTERFACE, GATEWAY_BASE) \ NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr) \ {return PyG_Base::QueryInterface(aIID, aInstancePtr);} \ @@ -570,4 +572,91 @@ private: PRBool created; }; +// Our classes. +// Hrm - So we can't have templates, eh?? +// preprocessor to the rescue, I guess. +#define PyXPCOM_INTERFACE_DECLARE(ClassName, InterfaceName, Methods ) \ + \ +extern struct PyMethodDef Methods[]; \ + \ +class ClassName : public Py_nsISupports \ +{ \ +public: \ + static PyXPCOM_TypeObject *type; \ + static Py_nsISupports *Constructor(nsISupports *pInitObj, const nsIID &iid) { \ + return new ClassName(pInitObj, iid); \ + } \ + static void InitType(PyObject *iidNameDict) { \ + type = new PyXPCOM_TypeObject( \ + #InterfaceName, \ + Py_nsISupports::type, \ + sizeof(ClassName), \ + Methods, \ + Constructor); \ + const nsIID &iid = NS_GET_IID(InterfaceName); \ + RegisterInterface(iid, type); \ + PyObject *iid_ob = Py_nsIID::PyObjectFromIID(iid); \ + PyDict_SetItemString(iidNameDict, "IID_"#InterfaceName, iid_ob); \ + Py_DECREF(iid_ob); \ + } \ +protected: \ + ClassName(nsISupports *p, const nsIID &iid) : \ + Py_nsISupports(p, iid, type) { \ + /* The IID _must_ be the IID of the interface we are wrapping! */ \ + NS_ABORT_IF_FALSE(iid.Equals(NS_GET_IID(InterfaceName)), "Bad IID"); \ + } \ +}; \ + \ +// End of PyXPCOM_INTERFACE_DECLARE macro + +#define PyXPCOM_ATTR_INTERFACE_DECLARE(ClassName, InterfaceName, Methods )\ + \ +extern struct PyMethodDef Methods[]; \ + \ +class ClassName : public Py_nsISupports \ +{ \ +public: \ + static PyXPCOM_TypeObject *type; \ + static Py_nsISupports *Constructor(nsISupports *pInitObj, const nsIID &iid) { \ + return new ClassName(pInitObj, iid); \ + } \ + static void InitType(PyObject *iidNameDict) { \ + type = new PyXPCOM_TypeObject( \ + #InterfaceName, \ + Py_nsISupports::type, \ + sizeof(ClassName), \ + Methods, \ + Constructor); \ + const nsIID &iid = NS_GET_IID(InterfaceName); \ + RegisterInterface(iid, type); \ + PyObject *iid_ob = Py_nsIID::PyObjectFromIID(iid); \ + PyDict_SetItemString(iidNameDict, "IID_"#InterfaceName, iid_ob); \ + Py_DECREF(iid_ob); \ +} \ + virtual PyObject *getattr(const char *name); \ + virtual int setattr(const char *name, PyObject *val); \ +protected: \ + ClassName(nsISupports *p, const nsIID &iid) : \ + Py_nsISupports(p, iid, type) { \ + /* The IID _must_ be the IID of the interface we are wrapping! */ \ + NS_ABORT_IF_FALSE(iid.Equals(NS_GET_IID(InterfaceName)), "Bad IID"); \ + } \ +}; \ + \ +// End of PyXPCOM_ATTR_INTERFACE_DECLARE macro + +#define PyXPCOM_INTERFACE_DEFINE(ClassName, InterfaceName, Methods ) \ +PyXPCOM_TypeObject *ClassName::type = NULL; + + +// And the classes +PyXPCOM_INTERFACE_DECLARE(Py_nsIComponentManager, nsIComponentManager, PyMethods_IComponentManager) +PyXPCOM_INTERFACE_DECLARE(Py_nsIInterfaceInfoManager, nsIInterfaceInfoManager, PyMethods_IInterfaceInfoManager) +PyXPCOM_INTERFACE_DECLARE(Py_nsIEnumerator, nsIEnumerator, PyMethods_IEnumerator) +PyXPCOM_INTERFACE_DECLARE(Py_nsISimpleEnumerator, nsISimpleEnumerator, PyMethods_ISimpleEnumerator) +PyXPCOM_INTERFACE_DECLARE(Py_nsIInterfaceInfo, nsIInterfaceInfo, PyMethods_IInterfaceInfo) +PyXPCOM_INTERFACE_DECLARE(Py_nsIServiceManager, nsIServiceManager, PyMethods_IServiceManager) +PyXPCOM_INTERFACE_DECLARE(Py_nsIInputStream, nsIInputStream, PyMethods_IInputStream) +PyXPCOM_ATTR_INTERFACE_DECLARE(Py_nsIClassInfo, nsIClassInfo, PyMethods_IClassInfo) + #endif // __PYXPCOM_H__ diff --git a/mozilla/extensions/python/xpcom/src/PyXPCOM_std.h b/mozilla/extensions/python/xpcom/src/PyXPCOM_std.h index 83e15001521..5f4bbf23708 100644 --- a/mozilla/extensions/python/xpcom/src/PyXPCOM_std.h +++ b/mozilla/extensions/python/xpcom/src/PyXPCOM_std.h @@ -34,12 +34,19 @@ // Main Mozilla cross-platform declarations. #include "xp_core.h" -#include -#include -#include -#include -#include -#include +#include "nsIAllocator.h" +#include "nsIWeakReference.h" +#include "nsIInterfaceInfoManager.h" +#include "nsIClassInfo.h" +#include "nsIComponentManager.h" +#include "nsIServiceManager.h" +#include "nsIInputStream.h" + + +#include "nsXPIDLString.h" +#include "nsCRT.h" +#include "xptcall.h" +#include "xpt_xdr.h" // This header is considered internal - hence // we can use it to trigger "exports" diff --git a/mozilla/extensions/python/xpcom/src/TypeObject.cpp b/mozilla/extensions/python/xpcom/src/TypeObject.cpp index da8e1419492..9a29d98685c 100644 --- a/mozilla/extensions/python/xpcom/src/TypeObject.cpp +++ b/mozilla/extensions/python/xpcom/src/TypeObject.cpp @@ -70,20 +70,13 @@ PyXPCOM_TypeObject::IsType(PyTypeObject *t) /*static*/PyObject * PyXPCOM_TypeObject::Py_getattr(PyObject *self, char *name) { - if (strcmp(name, "IID")==0) - return Py_nsIID::PyObjectFromIID( ((Py_nsISupports *)self)->m_iid ); - - PyXPCOM_TypeObject *this_type = (PyXPCOM_TypeObject *)self->ob_type; - return Py_FindMethodInChain(&this_type->chain, self, name); + return ((Py_nsISupports *)self)->getattr(name); } /*static*/int PyXPCOM_TypeObject::Py_setattr(PyObject *op, char *name, PyObject *v) { - char buf[128]; - sprintf(buf, "%s has read-only attributes", op->ob_type->tp_name ); - PyErr_SetString(PyExc_TypeError, buf); - return -1; + return ((Py_nsISupports *)op)->setattr(name, v); } // @pymethod int|Py_nsISupports|__cmp__|Implements XPCOM rules for object identity. diff --git a/mozilla/extensions/python/xpcom/src/loader/pyloader.cpp b/mozilla/extensions/python/xpcom/src/loader/pyloader.cpp index 1860cb08cc0..d231512fd84 100644 --- a/mozilla/extensions/python/xpcom/src/loader/pyloader.cpp +++ b/mozilla/extensions/python/xpcom/src/loader/pyloader.cpp @@ -129,6 +129,9 @@ extern "C" NS_EXPORT nsresult NSGetModule(nsIComponentManager *servMgr, LogError("Python initialization failed!\n"); return NS_ERROR_FAILURE; } +#ifndef NS_DEBUG + Py_OptimizeFlag = 1; +#endif AddStandardPaths(); PyObject *mod = PyImport_ImportModule("xpcom._xpcom"); if (mod==NULL) { diff --git a/mozilla/extensions/python/xpcom/src/makefile.win b/mozilla/extensions/python/xpcom/src/makefile.win index 7532a258ee9..d62ecbe3251 100755 --- a/mozilla/extensions/python/xpcom/src/makefile.win +++ b/mozilla/extensions/python/xpcom/src/makefile.win @@ -40,6 +40,7 @@ CPP_OBJS= \ .\$(OBJDIR)\PyGStub.obj \ .\$(OBJDIR)\PyGInputStream.obj \ .\$(OBJDIR)\PyGWeakReference.obj \ + .\$(OBJDIR)\PyIClassInfo.obj \ .\$(OBJDIR)\PyIComponentManager.obj \ .\$(OBJDIR)\PyIInputStream.obj \ .\$(OBJDIR)\PyIEnumerator.obj \ @@ -64,6 +65,7 @@ CPPSRCS = \ PyGStub.cpp \ PyGInputStream.cpp \ PyGWeakReference.cpp \ + PyIClassInfo.cpp \ PyIComponentManager.cpp \ PyIInputStream.cpp \ PyIEnumerator.cpp \ diff --git a/mozilla/extensions/python/xpcom/src/xpcom.cpp b/mozilla/extensions/python/xpcom/src/xpcom.cpp index d01d16e3897..2d5f4a04e7a 100644 --- a/mozilla/extensions/python/xpcom/src/xpcom.cpp +++ b/mozilla/extensions/python/xpcom/src/xpcom.cpp @@ -28,21 +28,19 @@ // (c) 2000, ActiveState corp. #include "PyXPCOM_std.h" -#include -#include -#include -#include -#include -#include -#include +#include "nsIFileSpec.h" +#include "nsSpecialSystemDirectory.h" +#include "nsIThread.h" +#include "nsISupportsPrimitives.h" +#include "nsIModule.h" #ifdef XP_WIN #define WIN32_LEAN_AND_MEAN #include "windows.h" #endif -#include -#include +#include "nsIEventQueue.h" +#include "nsIProxyObjectManager.h" PYXPCOM_EXPORT PyObject *PyXPCOM_Error = NULL; extern void PyXPCOM_InterpreterState_Ensure(); @@ -58,6 +56,15 @@ extern void PyXPCOM_InterpreterState_Ensure(); #endif // XP_WIN +PyXPCOM_INTERFACE_DEFINE(Py_nsIComponentManager, nsIComponentManager, PyMethods_IComponentManager) +PyXPCOM_INTERFACE_DEFINE(Py_nsIInterfaceInfoManager, nsIInterfaceInfoManager, PyMethods_IInterfaceInfoManager) +PyXPCOM_INTERFACE_DEFINE(Py_nsIEnumerator, nsIEnumerator, PyMethods_IEnumerator) +PyXPCOM_INTERFACE_DEFINE(Py_nsISimpleEnumerator, nsISimpleEnumerator, PyMethods_ISimpleEnumerator) +PyXPCOM_INTERFACE_DEFINE(Py_nsIInterfaceInfo, nsIInterfaceInfo, PyMethods_IInterfaceInfo) +PyXPCOM_INTERFACE_DEFINE(Py_nsIServiceManager, nsIServiceManager, PyMethods_IServiceManager) +PyXPCOM_INTERFACE_DEFINE(Py_nsIInputStream, nsIInputStream, PyMethods_IInputStream) +PyXPCOM_INTERFACE_DEFINE(Py_nsIClassInfo, nsIClassInfo, PyMethods_IClassInfo) + //////////////////////////////////////////////////////////// // This is the main entry point called by the Python component // loader. @@ -114,53 +121,6 @@ done: return nr; } -// Hrm - So we can't have templates, eh?? -// preprocessor to the rescue, I guess. -#define PyXPCOM_INTERFACE_DEFINE(ClassName, InterfaceName, Methods ) \ - \ -extern struct PyMethodDef Methods[]; \ - \ -class ClassName : public Py_nsISupports \ -{ \ -public: \ - static PyXPCOM_TypeObject *type; \ - static Py_nsISupports *Constructor(nsISupports *pInitObj, const nsIID &iid) { \ - return new ClassName(pInitObj, iid); \ - } \ - static void InitType(PyObject *iidNameDict) { \ - type = new PyXPCOM_TypeObject( \ - #InterfaceName, \ - Py_nsISupports::type, \ - sizeof(ClassName), \ - Methods, \ - Constructor); \ - const nsIID &iid = NS_GET_IID(InterfaceName); \ - RegisterInterface(iid, type); \ - PyObject *iid_ob = Py_nsIID::PyObjectFromIID(iid); \ - PyDict_SetItemString(iidNameDict, "IID_"#InterfaceName, iid_ob); \ - Py_DECREF(iid_ob); \ - } \ -protected: \ - ClassName(nsISupports *p, const nsIID &iid) : \ - Py_nsISupports(p, iid, type) { \ - /* The IID _must_ be the IID of the interface we are wrapping! */ \ - NS_ABORT_IF_FALSE(iid.Equals(NS_GET_IID(InterfaceName)), "Bad IID"); \ - } \ -}; \ - \ -PyXPCOM_TypeObject *ClassName::type = NULL; \ - \ -// End of PyXPCOM_INTERFACE_DEFINE macro - -// And the classes -PyXPCOM_INTERFACE_DEFINE(Py_nsIComponentManager, nsIComponentManager, PyMethods_IComponentManager) -PyXPCOM_INTERFACE_DEFINE(Py_nsIInterfaceInfoManager, nsIInterfaceInfoManager, PyMethods_IInterfaceInfoManager) -PyXPCOM_INTERFACE_DEFINE(Py_nsIEnumerator, nsIEnumerator, PyMethods_IEnumerator) -PyXPCOM_INTERFACE_DEFINE(Py_nsISimpleEnumerator, nsISimpleEnumerator, PyMethods_ISimpleEnumerator) -PyXPCOM_INTERFACE_DEFINE(Py_nsIInterfaceInfo, nsIInterfaceInfo, PyMethods_IInterfaceInfo) -PyXPCOM_INTERFACE_DEFINE(Py_nsIServiceManager, nsIServiceManager, PyMethods_IServiceManager) -PyXPCOM_INTERFACE_DEFINE(Py_nsIInputStream, nsIInputStream, PyMethods_IInputStream) - // "boot-strap" methods - interfaces we need to get the base // interface support! @@ -302,7 +262,8 @@ static PyObject * PyXPCOMMethod_WrapObject(PyObject *self, PyObject *args) { PyObject *ob, *obIID; - if (!PyArg_ParseTuple(args, "OO", &ob, &obIID)) + int bWrapClient = 1; + if (!PyArg_ParseTuple(args, "OO|i", &ob, &obIID, &bWrapClient)) return NULL; nsIID iid; @@ -319,7 +280,7 @@ PyXPCOMMethod_WrapObject(PyObject *self, PyObject *args) AddDefaultGateway(ob, ret); // inject a weak reference to myself into the instance. // Now wrap it in an interface. - return Py_nsISupports::PyObjectFromInterface(ret, iid, PR_FALSE); + return Py_nsISupports::PyObjectFromInterface(ret, iid, PR_FALSE, bWrapClient); } // @pymethod int|pythoncom|_GetInterfaceCount|Retrieves the number of interface objects currently in existance @@ -600,6 +561,7 @@ init_xpcom() { REGISTER_IID(nsIFactory); REGISTER_IID(nsIWeakReference); REGISTER_IID(nsISupportsWeakReference); + REGISTER_IID(nsIClassInfo); // Register our custom interfaces. Py_nsISupports::InitType(); @@ -610,6 +572,7 @@ init_xpcom() { Py_nsIInterfaceInfo::InitType(dict); Py_nsIServiceManager::InitType(dict); Py_nsIInputStream::InitType(dict); + Py_nsIClassInfo::InitType(dict); // We have special support for proxies - may as well add their constants! REGISTER_INT(PROXY_SYNC); diff --git a/mozilla/extensions/python/xpcom/test/output/test_misc b/mozilla/extensions/python/xpcom/test/output/test_misc index 94e971f5805..6c3cec3e4c1 100644 --- a/mozilla/extensions/python/xpcom/test/output/test_misc +++ b/mozilla/extensions/python/xpcom/test/output/test_misc @@ -1,9 +1,10 @@ test_misc Running all tests - use '-h' to see command-line options... -The netscape sample worked! +Dumping every interface I can find - please wait +(verbosity is turned off, so I'm not actually going to print them) +Finished dumping all the interfaces. Enumerated all the ContractIDs xpcom object hashing tests seemed to work -Dumping every interface I can find - please wait -(verbosity is turned off, so Im not actually going to print them) -Finished dumping all the interfaces. The IID tests seemed to work +The netscape sample worked! +The netscape sample worked with interface flattening! diff --git a/mozilla/extensions/python/xpcom/test/test_components.py b/mozilla/extensions/python/xpcom/test/test_components.py index 5e6e7935b6e..9366031a7aa 100644 --- a/mozilla/extensions/python/xpcom/test/test_components.py +++ b/mozilla/extensions/python/xpcom/test/test_components.py @@ -49,8 +49,8 @@ def test_interfaces(): def test_classes(): # Need a well-known contractID here? - prog_id = "@mozilla.org/filelocator;1" - clsid = xpcom.components.ID("{78043e01-e603-11d2-915f-f08a208628fc}") + prog_id = "@mozilla.org/supports-array;1" + clsid = xpcom.components.ID("{bda17d50-0d6b-11d3-9331-00104ba0fd40}") # Check we can create the instance (dont check we can do anything with it tho!) klass = xpcom.components.classes[prog_id] diff --git a/mozilla/extensions/python/xpcom/test/test_isupports_primitives.py b/mozilla/extensions/python/xpcom/test/test_isupports_primitives.py index 4fa15c92f48..3eff19e49c0 100644 --- a/mozilla/extensions/python/xpcom/test/test_isupports_primitives.py +++ b/mozilla/extensions/python/xpcom/test/test_isupports_primitives.py @@ -73,7 +73,7 @@ class ImplicitSupportsFloat: def test(): import xpcom.server, xpcom.client ob = xpcom.server.WrapObject( NoSupportsString(), components.interfaces.nsISupports) - if not str(ob).startswith("