From cd03200213d8a3e18018bb78bdec3fe4fb6987ae Mon Sep 17 00:00:00 2001 From: "mhammond%skippinet.com.au" Date: Wed, 5 Oct 2005 22:21:35 +0000 Subject: [PATCH] Go further in the concept of a "wrapped native". DOM objects get their own nsISupports wrapper, which has support in context.py for expandos, and all object returned by these objects are also this custom object. git-svn-id: svn://10.0.0.236/branches/DOM_AGNOSTIC_BRANCH@181687 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/extensions/python/dom/src/Makefile.in | 1 + .../extensions/python/dom/src/nsPyContext.cpp | 31 ++-- .../extensions/python/dom/src/nsPyContext.h | 2 +- mozilla/extensions/python/dom/src/nsPyDOM.h | 41 +++++ .../python/dom/src/nsPyDOMISupports.cpp | 158 ++++++++++++++++++ .../extensions/python/dom/src/nsPyRuntime.cpp | 15 +- 6 files changed, 220 insertions(+), 28 deletions(-) create mode 100644 mozilla/extensions/python/dom/src/nsPyDOM.h create mode 100644 mozilla/extensions/python/dom/src/nsPyDOMISupports.cpp diff --git a/mozilla/extensions/python/dom/src/Makefile.in b/mozilla/extensions/python/dom/src/Makefile.in index af8b45fed3d..fb9b346fb2d 100644 --- a/mozilla/extensions/python/dom/src/Makefile.in +++ b/mozilla/extensions/python/dom/src/Makefile.in @@ -32,6 +32,7 @@ CPPSRCS = \ nsPyContext.cpp \ nsPyRuntime.cpp \ nsPyDOMModule.cpp \ + nsPyDOMISupports.cpp \ $(NULL) include $(topsrcdir)/config/config.mk diff --git a/mozilla/extensions/python/dom/src/nsPyContext.cpp b/mozilla/extensions/python/dom/src/nsPyContext.cpp index 1e79ecba019..14d902211c3 100644 --- a/mozilla/extensions/python/dom/src/nsPyContext.cpp +++ b/mozilla/extensions/python/dom/src/nsPyContext.cpp @@ -78,6 +78,7 @@ AtomToEventHandlerName(nsIAtom *aName) nsPythonContext::nsPythonContext() : mIsInitialized(PR_FALSE), + mScriptGlobal(nsnull), mOwner(nsnull), mScriptsEnabled(PR_TRUE), mProcessingScriptTag(PR_FALSE), @@ -143,14 +144,15 @@ nsresult nsPythonContext::HandlePythonError() PRBool outOfMem = PyErr_GivenExceptionMatches(exc, PyExc_MemoryError); nsCAutoString cerrMsg; - PyXPCOM_FormatCurrentException(cerrMsg); + PyXPCOM_FormatGivenException(cerrMsg, exc, typ, tb); nsAutoString errMsg; CopyUTF8toUTF16(cerrMsg, errMsg); + NS_ASSERTION(!errMsg.IsEmpty(), "Failed to extract a Python error message"); errorevent.errorMsg = errMsg.get(); nsEventStatus status = nsEventStatus_eIgnore; // Handle the script error before we restore the exception. - if (mScriptGlobal && !outOfMem) { + if (mScriptGlobal != nsnull && !outOfMem) { mScriptGlobal->HandleScriptError(&errorevent, &status); } @@ -198,9 +200,7 @@ nsPythonContext::InitContext(nsIScriptGlobalObject *aGlobalObject) if (aGlobalObject) { // must build the object with nsISupports, so it gets the automagic // interface flattening (I guess that is a bug in pyxpcom?) - obGlobal = Py_nsISupports::PyObjectFromInterface(aGlobalObject, - NS_GET_IID(nsISupports), - PR_TRUE, PR_FALSE); + obGlobal = PyObject_FromDOMnsISupports(mDelegate, aGlobalObject); if (!obGlobal) return HandlePythonError(); } else { @@ -401,9 +401,7 @@ nsPythonContext::BindCompiledEventHandler(nsISupports *aTarget, void *aScope, CEnterLeavePython _celp; PyObject *obTarget; - obTarget = Py_nsISupports::PyObjectFromInterface(aTarget, - NS_GET_IID(nsISupports), - PR_TRUE, PR_FALSE); + obTarget = PyObject_FromDOMnsISupports(mDelegate, aTarget); if (!obTarget) return HandlePythonError(); @@ -448,15 +446,11 @@ nsPythonContext::CallEventHandler(nsISupports *aTarget, void *aScope, void* aHan CEnterLeavePython _celp; PyObject *obTarget, *obArgv; - obTarget = Py_nsISupports::PyObjectFromInterface(aTarget, - NS_GET_IID(nsISupports), - PR_TRUE, PR_FALSE); + obTarget = PyObject_FromDOMnsISupports(mDelegate, aTarget); if (!obTarget) return HandlePythonError(); - obArgv = Py_nsISupports::PyObjectFromInterface(aargv, - NS_GET_IID(nsIArray), - PR_TRUE, PR_TRUE); + obArgv = PyObject_FromDOMnsISupports(mDelegate, aargv); if (!obArgv) { Py_DECREF(obTarget); return HandlePythonError(); @@ -489,9 +483,7 @@ nsPythonContext::GetBoundEventHandler(nsISupports* aTarget, void *aScope, CEnterLeavePython _celp; PyObject *obTarget; - obTarget = Py_nsISupports::PyObjectFromInterface(aTarget, - NS_GET_IID(nsISupports), - PR_TRUE, PR_FALSE); + obTarget = PyObject_FromDOMnsISupports(mDelegate, aTarget); if (!obTarget) return HandlePythonError(); @@ -523,9 +515,7 @@ nsPythonContext::SetProperty(void *aTarget, const char *aPropName, nsISupports * CEnterLeavePython _celp; PyObject *obVal; - obVal = Py_nsISupports::PyObjectFromInterface(aVal, - NS_GET_IID(nsISupports), - PR_TRUE, PR_FALSE); + obVal = PyObject_FromDOMnsISupports(mDelegate, aVal); if (!obVal) return HandlePythonError(); @@ -748,6 +738,7 @@ nsPythonContext::FinalizeClasses(void *aGlobalObj) "O", aGlobalObj); Py_XDECREF(ret); + mScriptGlobal = nsnull; return HandlePythonError(); } diff --git a/mozilla/extensions/python/dom/src/nsPyContext.h b/mozilla/extensions/python/dom/src/nsPyContext.h index 3f6cb38f2bd..4a6ca7a3ae6 100644 --- a/mozilla/extensions/python/dom/src/nsPyContext.h +++ b/mozilla/extensions/python/dom/src/nsPyContext.h @@ -37,7 +37,7 @@ #include "nsIScriptContext.h" #include "nsITimer.h" -#include "PyXPCOM.h" +#include "nsPyDOM.h" class nsIScriptObjectOwner; class nsIArray; diff --git a/mozilla/extensions/python/dom/src/nsPyDOM.h b/mozilla/extensions/python/dom/src/nsPyDOM.h new file mode 100644 index 00000000000..a2c6ccbbb3f --- /dev/null +++ b/mozilla/extensions/python/dom/src/nsPyDOM.h @@ -0,0 +1,41 @@ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is mozilla.org. + * Portions created by the Initial Developer are Copyright (C) 2005 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mark Hammond (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 ***** */ + +#include "PyXPCOM.h" + +PyObject *PyObject_FromDOMnsISupports(PyObject *pycontext, nsISupports *pis, + PRBool bMakeNicePyObject = PR_TRUE); +void PyInit_DOMnsISupports(); diff --git a/mozilla/extensions/python/dom/src/nsPyDOMISupports.cpp b/mozilla/extensions/python/dom/src/nsPyDOMISupports.cpp new file mode 100644 index 00000000000..57ea44fc565 --- /dev/null +++ b/mozilla/extensions/python/dom/src/nsPyDOMISupports.cpp @@ -0,0 +1,158 @@ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is mozilla.org. + * Portions created by the Initial Developer are Copyright (C) 2005 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mark Hammond (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 ***** */ + +#include "PyXPCOM.h" + +static PyObject *g_obFuncMakeInterface = NULL; + +PyObject *PyObject_FromDOMnsISupports(PyObject *pycontext, nsISupports *pis, + PRBool bMakeNicePyObject = PR_TRUE); + +struct PyMethodDef +Py_DOMnsISupports_Methods[] = +{ + {NULL} +}; + +class Py_DOMnsISupports : public Py_nsISupports +{ +public: + static PyXPCOM_TypeObject *type; + static void InitType() { + type = new PyXPCOM_TypeObject( + "DOMISupports", + Py_nsISupports::type, + sizeof(Py_DOMnsISupports), + Py_DOMnsISupports_Methods, + nsnull); + const nsIID &iid = NS_GET_IID(nsISupports); + // Don't RegisterInterface! + // RegisterInterface(iid, type); + } + //virtual PyObject *getattr(const char *name); + //virtual int setattr(const char *name, PyObject *val); + virtual PyObject *MakeInterfaceResult(nsISupports *ps, const nsIID &iid, + PRBool bMakeNicePyObject = PR_TRUE) + { + if (!iid.Equals(NS_GET_IID(nsIClassInfo))) + return PyObject_FromDOMnsISupports(m_pycontext, ps, bMakeNicePyObject); + return Py_nsISupports::MakeInterfaceResult(ps, iid, bMakeNicePyObject); + } + + Py_DOMnsISupports(PyObject *pycontext, nsISupports *p, const nsIID &iid) : + Py_nsISupports(p, iid, type), + m_pycontext(pycontext) { + /* The IID _must_ be the IID of the interface we are wrapping! */ + //NS_ABORT_IF_FALSE(iid.Equals(NS_GET_IID(InterfaceName)), "Bad IID"); + Py_INCREF(pycontext); + } + virtual ~Py_DOMnsISupports() { + Py_DECREF(m_pycontext); + } + static PyObject *MakeDefaultWrapper(PyObject *pycontext, + PyObject *pyis, const nsIID &iid); +protected: + PyObject *m_pycontext; +}; + + +PyObject *PyObject_FromDOMnsISupports(PyObject *pycontext, nsISupports *pis, + PRBool bMakeNicePyObject /* = PR_TRUE */) +{ + if (pis==NULL) { + Py_INCREF(Py_None); + return Py_None; + } + + nsIID iid = NS_GET_IID(nsISupports); + Py_DOMnsISupports *ret = new Py_DOMnsISupports(pycontext, pis, iid); + pis->AddRef(); + if (ret && bMakeNicePyObject) + return Py_DOMnsISupports::MakeDefaultWrapper(pycontext, ret, iid); + return ret; +} + +// Call back into the Python context +PyObject * +Py_DOMnsISupports::MakeDefaultWrapper(PyObject *pycontext, + PyObject *pyis, + const nsIID &iid) +{ + NS_PRECONDITION(pyis, "NULL pyobject!"); + PyObject *obIID = NULL; + PyObject *args = NULL; + PyObject *mod = NULL; + PyObject *ret = NULL; + + obIID = Py_nsIID::PyObjectFromIID(iid); + if (obIID==NULL) + goto done; + + if (g_obFuncMakeInterface==NULL) { + PyObject *mod = PyImport_ImportModule("nsdom.context"); + if (mod) + g_obFuncMakeInterface = PyObject_GetAttrString(mod, "MakeInterfaceResult"); + Py_XDECREF(mod); + } + if (g_obFuncMakeInterface==NULL) goto done; + + args = Py_BuildValue("OOO", pycontext, pyis, obIID); + if (args==NULL) goto done; + ret = PyEval_CallObject(g_obFuncMakeInterface, args); +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 result failed\n"); + PyErr_Clear(); + } + Py_XDECREF(mod); + Py_XDECREF(args); + Py_XDECREF(obIID); + if (ret==NULL) // eek - error - return the original with no refcount mod. + ret = pyis; + else + // no error - decref the old object + Py_DECREF(pyis); + // return our obISupports. If NULL, we are really hosed and nothing we can do. + return ret; +} + +void PyInit_DOMnsISupports() +{ + Py_DOMnsISupports::InitType(); +} +PyXPCOM_TypeObject *Py_DOMnsISupports::type = NULL; +//PyXPCOM_INTERFACE_DEFINE(Py_DOMnsISupports, ?, PyMethods_DOMnsISupports) diff --git a/mozilla/extensions/python/dom/src/nsPyRuntime.cpp b/mozilla/extensions/python/dom/src/nsPyRuntime.cpp index e828216d1bc..9237c73035b 100644 --- a/mozilla/extensions/python/dom/src/nsPyRuntime.cpp +++ b/mozilla/extensions/python/dom/src/nsPyRuntime.cpp @@ -46,6 +46,8 @@ extern void init_nsdom(); +static PRBool initialized = PR_FALSE; + // QueryInterface implementation for nsPythonRuntime NS_INTERFACE_MAP_BEGIN(nsPythonRuntime) NS_INTERFACE_MAP_ENTRY(nsILanguageRuntime) @@ -58,11 +60,14 @@ NS_IMPL_RELEASE(nsPythonRuntime) nsresult nsPythonRuntime::CreateContext(nsIScriptContext **ret) { - if (!Py_IsInitialized()) { + if (!Py_IsInitialized()) Py_Initialize(); + if (!initialized) { PyXPCOM_Globals_Ensure(); + PyInit_DOMnsISupports(); + init_nsdom(); + initialized = PR_TRUE; } - init_nsdom(); *ret = new nsPythonContext(); if (!ret) return NS_ERROR_OUT_OF_MEMORY; @@ -222,14 +227,10 @@ static struct PyMethodDef methods[]= // The module init code. // // *NOT* called by Python - this is not a regular Python module. -static PRBool have_init = PR_FALSE; - +// Caller must ensure only called once! void init_nsdom() { - if (have_init) - return; CEnterLeavePython _celp; // Create the module and add the functions Py_InitModule("_nsdom", methods); - have_init = PR_TRUE; }