diff --git a/mozilla/extensions/python/dom/src/Makefile.in b/mozilla/extensions/python/dom/src/Makefile.in index fb9b346fb2d..12a98273701 100644 --- a/mozilla/extensions/python/dom/src/Makefile.in +++ b/mozilla/extensions/python/dom/src/Makefile.in @@ -13,7 +13,7 @@ include $(DEPTH)/config/autoconf.mk LIBRARY_NAME = pydom IS_COMPONENT = 1 REQUIRES = pyxpcom xpcom string xpcom_obsolete dom \ - widget js gfx gklayout $(NULL) + widget js gfx gklayout content layout necko $(NULL) MOZILLA_INTERNAL_API = 1 FORCE_SHARED_LIB = 1 diff --git a/mozilla/extensions/python/dom/src/nsPyContext.cpp b/mozilla/extensions/python/dom/src/nsPyContext.cpp index aa27bf35341..8f800d74e88 100644 --- a/mozilla/extensions/python/dom/src/nsPyContext.cpp +++ b/mozilla/extensions/python/dom/src/nsPyContext.cpp @@ -199,9 +199,8 @@ nsPythonContext::InitContext(nsIScriptGlobalObject *aGlobalObject) PyObject *obGlobal; if (aGlobalObject) { - // must build the object with nsISupports, so it gets the automagic - // interface flattening (I guess that is a bug in pyxpcom?) - obGlobal = PyObject_FromDOMnsISupports(mDelegate, aGlobalObject); + obGlobal = PyObject_FromNSDOMInterface(mDelegate, aGlobalObject, + NS_GET_IID(nsIScriptGlobalObject)); if (!obGlobal) return HandlePythonError(); } else { @@ -402,7 +401,7 @@ nsPythonContext::BindCompiledEventHandler(nsISupports *aTarget, void *aScope, CEnterLeavePython _celp; PyObject *obTarget; - obTarget = PyObject_FromDOMnsISupports(mDelegate, aTarget); + obTarget = PyObject_FromNSDOMInterface(mDelegate, aTarget); if (!obTarget) return HandlePythonError(); @@ -447,11 +446,11 @@ nsPythonContext::CallEventHandler(nsISupports *aTarget, void *aScope, void* aHan CEnterLeavePython _celp; PyObject *obTarget, *obArgv; - obTarget = PyObject_FromDOMnsISupports(mDelegate, aTarget); + obTarget = PyObject_FromNSDOMInterface(mDelegate, aTarget); if (!obTarget) return HandlePythonError(); - obArgv = PyObject_FromDOMnsISupports(mDelegate, aargv); + obArgv = PyObject_FromNSDOMInterface(mDelegate, aargv); if (!obArgv) { Py_DECREF(obTarget); return HandlePythonError(); @@ -484,7 +483,7 @@ nsPythonContext::GetBoundEventHandler(nsISupports* aTarget, void *aScope, CEnterLeavePython _celp; PyObject *obTarget; - obTarget = PyObject_FromDOMnsISupports(mDelegate, aTarget); + obTarget = PyObject_FromNSDOMInterface(mDelegate, aTarget); if (!obTarget) return HandlePythonError(); @@ -516,7 +515,7 @@ nsPythonContext::SetProperty(void *aTarget, const char *aPropName, nsISupports * CEnterLeavePython _celp; PyObject *obVal; - obVal = PyObject_FromDOMnsISupports(mDelegate, aVal); + obVal = PyObject_FromNSDOMInterface(mDelegate, aVal); if (!obVal) return HandlePythonError(); diff --git a/mozilla/extensions/python/dom/src/nsPyDOM.h b/mozilla/extensions/python/dom/src/nsPyDOM.h index a2c6ccbbb3f..fce31b88da6 100644 --- a/mozilla/extensions/python/dom/src/nsPyDOM.h +++ b/mozilla/extensions/python/dom/src/nsPyDOM.h @@ -36,6 +36,7 @@ #include "PyXPCOM.h" -PyObject *PyObject_FromDOMnsISupports(PyObject *pycontext, nsISupports *pis, +PyObject *PyObject_FromNSDOMInterface(PyObject *pycontext, nsISupports *pis, + const nsIID &iid = NS_GET_IID(nsISupports), 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 index 57ea44fc565..78466c829fb 100644 --- a/mozilla/extensions/python/dom/src/nsPyDOMISupports.cpp +++ b/mozilla/extensions/python/dom/src/nsPyDOMISupports.cpp @@ -34,12 +34,7 @@ * * ***** END LICENSE BLOCK ***** */ -#include "PyXPCOM.h" - -static PyObject *g_obFuncMakeInterface = NULL; - -PyObject *PyObject_FromDOMnsISupports(PyObject *pycontext, nsISupports *pis, - PRBool bMakeNicePyObject = PR_TRUE); +#include "nsPyDOM.h" struct PyMethodDef Py_DOMnsISupports_Methods[] = @@ -68,7 +63,8 @@ public: PRBool bMakeNicePyObject = PR_TRUE) { if (!iid.Equals(NS_GET_IID(nsIClassInfo))) - return PyObject_FromDOMnsISupports(m_pycontext, ps, bMakeNicePyObject); + return PyObject_FromNSDOMInterface(m_pycontext, ps, + iid, bMakeNicePyObject); return Py_nsISupports::MakeInterfaceResult(ps, iid, bMakeNicePyObject); } @@ -89,7 +85,8 @@ protected: }; -PyObject *PyObject_FromDOMnsISupports(PyObject *pycontext, nsISupports *pis, +PyObject *PyObject_FromNSDOMInterface(PyObject *pycontext, nsISupports *pis, + const nsIID &iid, /* = nsISupports */ PRBool bMakeNicePyObject /* = PR_TRUE */) { if (pis==NULL) { @@ -97,7 +94,6 @@ PyObject *PyObject_FromDOMnsISupports(PyObject *pycontext, nsISupports *pis, return Py_None; } - nsIID iid = NS_GET_IID(nsISupports); Py_DOMnsISupports *ret = new Py_DOMnsISupports(pycontext, pis, iid); pis->AddRef(); if (ret && bMakeNicePyObject) @@ -113,33 +109,21 @@ Py_DOMnsISupports::MakeDefaultWrapper(PyObject *pycontext, { 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); + return PyObject_CallMethod(pycontext, "MakeInterfaceResult", + "OO", pyis, obIID); + if (ret==NULL) goto done; 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; diff --git a/mozilla/extensions/python/dom/src/nsPyRuntime.cpp b/mozilla/extensions/python/dom/src/nsPyRuntime.cpp index 9237c73035b..ee0d13c797b 100644 --- a/mozilla/extensions/python/dom/src/nsPyRuntime.cpp +++ b/mozilla/extensions/python/dom/src/nsPyRuntime.cpp @@ -41,8 +41,16 @@ #include "nsIScriptGlobalObject.h" #include "nsIScriptContext.h" #include "nsIScriptObjectPrincipal.h" +#include "nsIDOMEventReceiver.h" +#include "nsIAtomService.h" +#include "nsIEventListenerManager.h" #include "jsapi.h" #include "jscntxt.h" +#include "nsPIDOMWindow.h" + +// just for constants... +#include "nsIScriptContext.h" +#include "nsIScriptGlobalObject.h" extern void init_nsdom(); @@ -60,8 +68,12 @@ NS_IMPL_RELEASE(nsPythonRuntime) nsresult nsPythonRuntime::CreateContext(nsIScriptContext **ret) { - if (!Py_IsInitialized()) + if (!Py_IsInitialized()) { Py_Initialize(); +#ifndef NS_DEBUG + Py_OptimizeFlag = 1; +#endif // NS_DEBUG + } if (!initialized) { PyXPCOM_Globals_Ensure(); PyInit_DOMnsISupports(); @@ -203,7 +215,7 @@ PyObject *PyJSExec(PyObject *self, PyObject *args) lineNo, version, &scriptObject); - if (NS_SUCCEEDED(rv)) + if (NS_SUCCEEDED(rv) && scriptObject) rv = scriptContext->ExecuteScript(scriptObject, scope, &str, &bIsUndefined); Py_END_ALLOW_THREADS @@ -215,22 +227,281 @@ PyObject *PyJSExec(PyObject *self, PyObject *args) return Py_BuildValue("NN", PyObject_FromNSString(str), PyBool_FromLong(bIsUndefined)); // XXX - cleanup scriptObject??? } + +// Various helpers to avoid exposing non-scriptable interfaces when we only +// need one or 2 functions. +static PyObject *PyIsOuterWindow(PyObject *self, PyObject *args) +{ + PyObject *obTarget; + if (!PyArg_ParseTuple(args, "O", &obTarget)) + return NULL; + + // target + nsCOMPtr target; + if (!Py_nsISupports::InterfaceFromPyObject( + obTarget, + NS_GET_IID(nsPIDOMWindow), + getter_AddRefs(target), + PR_FALSE, PR_FALSE)) + return NULL; + + return PyBool_FromLong(target->IsOuterWindow()); +} + +static PyObject *PyGetCurrentInnerWindow(PyObject *self, PyObject *args) +{ + PyObject *obTarget; + if (!PyArg_ParseTuple(args, "O", &obTarget)) + return NULL; + + // target + nsCOMPtr target; + if (!Py_nsISupports::InterfaceFromPyObject( + obTarget, + NS_GET_IID(nsPIDOMWindow), + getter_AddRefs(target), + PR_FALSE, PR_FALSE)) + return NULL; + + return PyObject_FromNSInterface(target->GetCurrentInnerWindow(), + NS_GET_IID(nsISupports), PR_FALSE); +} +/*** +static PyObject *PyGetScriptContext(PyObject *self, PyObject *args) +{ + PyObject *obTarget; + if (!PyArg_ParseTuple(args, "O", &obTarget)) + return NULL; + + // target + nsCOMPtr target; + if (!Py_nsISupports::InterfaceFromPyObject( + obTarget, + NS_GET_IID(nsIScriptGlobalObject), + getter_AddRefs(target), + PR_FALSE, PR_FALSE)) + return NULL; + + nsCOMPtr ctxt(target->GetScriptContext(target) + + return PyObject_FromNSInterface(target->GetCurrentInnerWindow(), + NS_GET_IID(nsISupports), PR_FALSE); +} +***/ +// Avoid exposing the entire non-scriptable event listener interface +// We are exposing: +// +//nsEventListenerManager::AddScriptEventListener(nsISupports *aObject, +// nsIAtom *aName, +// const nsAString& aBody, +// PRUint32 aLanguage, +// PRBool aDeferCompilation, +// PRBool aPermitUntrustedEvents) +// +// Implementation of the above seems strange - if !aDeferCompilation then +// aBody is ignored (presumably to later be fetched via GetAttr + +static PyObject *PyAddScriptEventListener(PyObject *self, PyObject *args) +{ + PyObject *obTarget, *obBody; + char *name; + int lang = nsIProgrammingLanguage::PYTHON; + int defer, untrusted; + if (!PyArg_ParseTuple(args, "OsOii|i", &obTarget, &name, &obBody, + &defer, &untrusted, &lang)) + return NULL; + + // target + nsCOMPtr target; + if (!Py_nsISupports::InterfaceFromPyObject( + obTarget, + NS_GET_IID(nsISupports), + getter_AddRefs(target), + PR_FALSE, PR_FALSE)) + return NULL; + + nsAutoString body; + if (!PyObject_AsNSString(obBody, body)) + return NULL; + + // The receiver, to get the manager. + nsCOMPtr receiver(do_QueryInterface(target)); + if (!receiver) return PyXPCOM_BuildPyException(NS_ERROR_UNEXPECTED); + + nsCOMPtr manager; + receiver->GetListenerManager(getter_AddRefs(manager)); + if (!manager) return PyXPCOM_BuildPyException(NS_ERROR_UNEXPECTED); + + nsCOMPtr atom(do_GetAtom(nsDependentCString(name))); + if (!atom) return PyXPCOM_BuildPyException(NS_ERROR_UNEXPECTED); + + nsresult rv; + Py_BEGIN_ALLOW_THREADS + rv = manager->AddScriptEventListener(target, atom, body, lang, defer, + untrusted); + Py_END_ALLOW_THREADS + if (NS_FAILED(rv)) + return PyXPCOM_BuildPyException(rv); + Py_INCREF(Py_None); + return Py_None; +} + +// NS_IMETHOD RegisterScriptEventListener(nsIScriptContext *aContext, +// void *aScopeObject, +// nsISupports *aObject, +// nsIAtom* aName) = 0; +static PyObject *PyRegisterScriptEventListener(PyObject *self, PyObject *args) +{ + PyObject *obTarget, *obGlobal, *obScope; + char *name; + if (!PyArg_ParseTuple(args, "OOOs", &obGlobal, &obScope, &obTarget, &name)) + return NULL; + + nsCOMPtr isup; + if (!Py_nsISupports::InterfaceFromPyObject( + obGlobal, + NS_GET_IID(nsISupports), + getter_AddRefs(isup), + PR_FALSE, PR_FALSE)) + return NULL; + nsCOMPtr scriptGlobal = do_QueryInterface(isup); + if (scriptGlobal == nsnull) + return PyErr_Format(PyExc_TypeError, "Object is not an nsIScriptGlobal"); + nsIScriptContext *scriptContext = + scriptGlobal->GetLanguageContext(nsIProgrammingLanguage::PYTHON); + if (!scriptContext) + return PyErr_Format(PyExc_RuntimeError, "Can't find my context??"); + + // target + nsCOMPtr target; + if (!Py_nsISupports::InterfaceFromPyObject( + obTarget, + NS_GET_IID(nsISupports), + getter_AddRefs(target), + PR_FALSE, PR_FALSE)) + return NULL; + + // sob - I don't quite understand this, but things get upset when + // an outer window gets the event. + nsCOMPtr win(do_QueryInterface(target)); + if (win != nsnull && win->IsOuterWindow()) { + target = win->GetCurrentInnerWindow(); + } + // The receiver, to get the manager. + nsCOMPtr receiver(do_QueryInterface(target)); + if (!receiver) return PyXPCOM_BuildPyException(NS_ERROR_UNEXPECTED); + + nsCOMPtr manager; + receiver->GetListenerManager(getter_AddRefs(manager)); + if (!manager) return PyXPCOM_BuildPyException(NS_ERROR_UNEXPECTED); + + nsCOMPtr atom(do_GetAtom(nsDependentCString(name))); + if (!atom) return PyXPCOM_BuildPyException(NS_ERROR_UNEXPECTED); + + nsresult rv; + Py_BEGIN_ALLOW_THREADS + rv = manager->RegisterScriptEventListener(scriptContext, obScope, + target, atom); + Py_END_ALLOW_THREADS + if (NS_FAILED(rv)) + return PyXPCOM_BuildPyException(rv); + Py_INCREF(Py_None); + return Py_None; +} + +// NS_IMETHOD CompileScriptEventListener(nsIScriptContext *aContext, +// void *aScopeObject, +// nsISupports *aObject, +// nsIAtom* aName, +// PRBool *aDidCompile) = 0; +static PyObject *PyCompileScriptEventListener(PyObject *self, PyObject *args) +{ + PyObject *obTarget, *obGlobal, *obScope; + char *name; + if (!PyArg_ParseTuple(args, "OOOs", &obGlobal, &obScope, &obTarget, &name)) + return NULL; + + nsCOMPtr isup; + if (!Py_nsISupports::InterfaceFromPyObject( + obGlobal, + NS_GET_IID(nsISupports), + getter_AddRefs(isup), + PR_FALSE, PR_FALSE)) + return NULL; + nsCOMPtr scriptGlobal = do_QueryInterface(isup); + if (scriptGlobal == nsnull) + return PyErr_Format(PyExc_TypeError, "Object is not an nsIScriptGlobal"); + nsIScriptContext *scriptContext = + scriptGlobal->GetLanguageContext(nsIProgrammingLanguage::PYTHON); + if (!scriptContext) + return PyErr_Format(PyExc_RuntimeError, "Can't find my context??"); + + // target + nsCOMPtr target; + if (!Py_nsISupports::InterfaceFromPyObject( + obTarget, + NS_GET_IID(nsISupports), + getter_AddRefs(target), + PR_FALSE, PR_FALSE)) + return NULL; + + // sob - I don't quite understand this, but things get upset when + // an outer window gets the event. + nsCOMPtr win(do_QueryInterface(target)); + if (win != nsnull && win->IsOuterWindow()) { + target = win->GetCurrentInnerWindow(); + } + // The receiver, to get the manager. + nsCOMPtr receiver(do_QueryInterface(target)); + if (!receiver) return PyXPCOM_BuildPyException(NS_ERROR_UNEXPECTED); + + nsCOMPtr manager; + receiver->GetListenerManager(getter_AddRefs(manager)); + if (!manager) return PyXPCOM_BuildPyException(NS_ERROR_UNEXPECTED); + + nsCOMPtr atom(do_GetAtom(nsDependentCString(name))); + if (!atom) return PyXPCOM_BuildPyException(NS_ERROR_UNEXPECTED); + + nsresult rv; + PRBool didCompile; + Py_BEGIN_ALLOW_THREADS + rv = manager->CompileScriptEventListener(scriptContext, obScope, + target, atom, &didCompile); + Py_END_ALLOW_THREADS + if (NS_FAILED(rv)) + return PyXPCOM_BuildPyException(rv); + return PyBool_FromLong(didCompile); +} + // We also setup a "fake" module called nsdom with a few utility functions // available to python. static struct PyMethodDef methods[]= { {"JSExec", PyJSExec, 1}, + {"AddScriptEventListener", PyAddScriptEventListener, 1}, + {"RegisterScriptEventListener", PyRegisterScriptEventListener, 1}, + {"CompileScriptEventListener", PyCompileScriptEventListener, 1}, + {"GetCurrentInnerWindow", PyGetCurrentInnerWindow, 1}, + {"IsOuterWindow", PyIsOuterWindow, 1}, { NULL } }; //////////////////////////////////////////////////////////// // The module init code. // +#define REGISTER_IID(t) { \ + PyObject *iid_ob = Py_nsIID::PyObjectFromIID(NS_GET_IID(t)); \ + PyDict_SetItemString(dict, "IID_"#t, iid_ob); \ + Py_DECREF(iid_ob); \ + } + // *NOT* called by Python - this is not a regular Python module. // Caller must ensure only called once! void init_nsdom() { CEnterLeavePython _celp; // Create the module and add the functions - Py_InitModule("_nsdom", methods); + PyObject *oModule = Py_InitModule("_nsdom", methods); + PyObject *dict = PyModule_GetDict(oModule); + REGISTER_IID(nsIScriptGlobalObject); }