diff --git a/direct/src/plugin/p3dInstance.cxx b/direct/src/plugin/p3dInstance.cxx index f6d9f4b483..5a98e79bb1 100644 --- a/direct/src/plugin/p3dInstance.cxx +++ b/direct/src/plugin/p3dInstance.cxx @@ -20,8 +20,7 @@ #include "p3dSplashWindow.h" #include "p3dWinSplashWindow.h" #include "p3dObject.h" -#include "p3dNoneObject.h" -#include "p3dPythonObject.h" +#include "p3dNullObject.h" #include #include @@ -84,7 +83,6 @@ P3DInstance:: _packages.clear(); if (_splash_window != NULL) { - nout << "Deleting splash window in destructor\n" << flush; delete _splash_window; _splash_window = NULL; } @@ -93,8 +91,6 @@ P3DInstance:: // TODO: Is it possible for someone to delete an instance while a // download is still running? Who will crash when this happens? - - nout << "deleting instance " << this << "\n" << flush; } //////////////////////////////////////////////////////////////////// @@ -176,7 +172,6 @@ set_wparams(const P3DWindowParams &wparams) { P3D_object *P3DInstance:: get_panda_script_object() const { assert(_session != NULL); - nout << "Called P3DInstance::get_panda_script_object()\n"; TiXmlDocument *doc = new TiXmlDocument; TiXmlDeclaration *decl = new TiXmlDeclaration("1.0", "utf-8", ""); @@ -186,7 +181,6 @@ get_panda_script_object() const { doc->LinkEndChild(decl); doc->LinkEndChild(xcommand); TiXmlDocument *response = _session->command_and_response(doc); - nout << "response pointer: " << response << "\n" << flush; P3D_object *result = NULL; if (response != NULL) { @@ -200,10 +194,10 @@ get_panda_script_object() const { delete response; } - nout << "Returning " << result << "\n" << flush; - if (result != NULL) { - nout << "result = " << *result << "\n" << flush; + if (result == NULL) { + result = new P3DNullObject; } + return result; } @@ -217,7 +211,6 @@ get_panda_script_object() const { //////////////////////////////////////////////////////////////////// void P3DInstance:: set_browser_script_object(P3D_object *browser_script_object) { - nout << "Called P3DInstance::set_browser_script_object()\n"; if (browser_script_object != _browser_script_object) { if (_browser_script_object != NULL) { P3D_OBJECT_FINISH(_browser_script_object); @@ -265,8 +258,6 @@ get_request() { } RELEASE_LOCK(_request_lock); - nout << "get_request: " << result << "\n" << flush; - if (result != NULL) { switch (result->_request_type) { case P3D_RT_notify: @@ -295,8 +286,6 @@ get_request() { //////////////////////////////////////////////////////////////////// void P3DInstance:: add_request(P3D_request *request) { - nout << "Instance " << this << " add_request(" << request->_request_type - << ")\n" << flush; request->_instance = this; ACQUIRE_LOCK(_request_lock); @@ -353,7 +342,6 @@ feed_url_stream(int unique_id, if (!download_ok || download->get_download_finished()) { // All done. - nout << "completed download " << unique_id << "\n" << flush; _downloads.erase(di); delete download; } @@ -398,9 +386,6 @@ start_download(P3DDownload *download) { bool inserted = _downloads.insert(Downloads::value_type(download_id, download)).second; assert(inserted); - nout << "beginning download " << download_id << ": " << download->get_url() - << "\n" << flush; - P3D_request *request = new P3D_request; request->_request_type = P3D_RT_get_url; request->_request._get_url._url = strdup(download->get_url().c_str()); @@ -489,10 +474,8 @@ handle_notify_request(P3D_request *request) { if (strcmp(message, "onwindowopen") == 0) { // The process told us that it just succesfully opened its // window. - nout << "Instance " << this << " got onwindowopen\n" << flush; _instance_window_opened = true; if (_splash_window != NULL) { - nout << "Deleting splash window\n" << flush; delete _splash_window; _splash_window = NULL; } @@ -515,14 +498,7 @@ handle_script_request(P3D_request *request) { case P3D_SO_get_property: { P3D_object *result = P3D_OBJECT_GET_PROPERTY(object, request->_request._script._property_name); - nout << "get_property, object = " << object << "\n"; - if (object != NULL) { - nout << " *object = " << *object << "\n" << flush; - } - nout << "result = " << result << "\n" << flush; - if (result != NULL) { - nout << " *result = " << *result << "\n" << flush; - } + // We've got the property value; feed it back down to the // subprocess. TiXmlDocument *doc = new TiXmlDocument; @@ -546,11 +522,6 @@ handle_script_request(P3D_request *request) { { bool result = P3D_OBJECT_SET_PROPERTY(object, request->_request._script._property_name, request->_request._script._value); - nout << "set_property, object = " << object << "\n"; - if (object != NULL) { - nout << " *object = " << *object << "\n" << flush; - } - nout << "result = " << result << "\n" << flush; // Feed the result back down to the subprocess. TiXmlDocument *doc = new TiXmlDocument; @@ -575,11 +546,6 @@ handle_script_request(P3D_request *request) { { bool result = P3D_OBJECT_SET_PROPERTY(object, request->_request._script._property_name, NULL); - nout << "del_property, object = " << object << "\n"; - if (object != NULL) { - nout << " *object = " << *object << "\n" << flush; - } - nout << "result = " << result << "\n" << flush; // Feed the result back down to the subprocess. TiXmlDocument *doc = new TiXmlDocument; @@ -634,8 +600,6 @@ make_splash_window() { string filename = name; free(name); - nout << "Downloading splash image into " << filename << "\n"; - // Start downloading the requested splash image. SplashDownload *download = new SplashDownload(this); download->set_url(splash_image_url); diff --git a/direct/src/plugin/p3dPythonRun.cxx b/direct/src/plugin/p3dPythonRun.cxx index 22956d4459..e476eaa8e1 100755 --- a/direct/src/plugin/p3dPythonRun.cxx +++ b/direct/src/plugin/p3dPythonRun.cxx @@ -191,14 +191,12 @@ run_python() { task_mgr->add(_check_comm_task); // Finally, get lost in taskMgr.run(). - nout << "calling run()\n"; PyObject *done = PyObject_CallMethod(_taskMgr, (char *)"run", (char *)""); if (done == NULL) { PyErr_Print(); return false; } Py_DECREF(done); - nout << "done calling run()\n"; return true; } @@ -211,7 +209,6 @@ run_python() { //////////////////////////////////////////////////////////////////// void P3DPythonRun:: handle_command(TiXmlDocument *doc) { - nout << "got command: " << *doc << "\n"; TiXmlElement *xcommand = doc->FirstChildElement("command"); if (xcommand != NULL) { bool needs_response = false; @@ -270,7 +267,6 @@ handle_command(TiXmlDocument *doc) { xresponse->SetAttribute("response_id", want_response_id); doc.LinkEndChild(decl); doc.LinkEndChild(xresponse); - nout << "sending " << doc << "\n" << flush; _pipe_write << doc << flush; } } @@ -298,7 +294,7 @@ handle_pyobj_command(TiXmlElement *xcommand, bool needs_response, if (op != NULL) { if (strcmp(op, "get_panda_script_object") == 0) { // Get Panda's toplevel Python object. - PyObject *obj = PyObject_GetAttrString(_runner, "scriptRoot"); + PyObject *obj = PyObject_CallMethod(_runner, "getPandaScriptObject", (char *)""); if (obj != NULL) { xresponse->LinkEndChild(pyobj_to_xml(obj)); Py_DECREF(obj); @@ -417,7 +413,6 @@ handle_pyobj_command(TiXmlElement *xcommand, bool needs_response, } if (needs_response) { - nout << "sending " << doc << "\n" << flush; _pipe_write << doc << flush; } } @@ -554,23 +549,19 @@ py_request_func(PyObject *args) { return NULL; } - nout << "Waiting for script_response " << response_id << "\n"; TiXmlDocument *doc = wait_script_response(response_id); - nout << "got: " << *doc << "\n"; TiXmlElement *xcommand = doc->FirstChildElement("command"); assert(xcommand != NULL); TiXmlElement *xvalue = xcommand->FirstChildElement("value"); PyObject *value = NULL; if (xvalue != NULL) { - nout << "Converting xvalue: " << *xvalue << "\n"; value = xml_to_pyobj(xvalue); } else { // An absence of a element means a NULL pointer. value = _null; Py_INCREF(value); } - nout << "Got script_response " << response_id << ", xvalue = " << xvalue << "\n"; delete doc; Py_DECREF(extra_args); @@ -594,7 +585,6 @@ py_request_func(PyObject *args) { } xrequest->SetAttribute("message", message); - nout << "sending " << doc << "\n" << flush; _pipe_write << doc << flush; } else if (strcmp(request_type, "script") == 0) { @@ -619,25 +609,8 @@ py_request_func(PyObject *args) { TiXmlElement *xvalue = pyobj_to_xml(value); xrequest->LinkEndChild(xvalue); - nout << "sending " << doc << "\n" << flush; _pipe_write << doc << flush; - /* - } else if (strcmp(request_type, "evaluate") == 0) { - // An evaluate request. - const char *expression; - int unique_id; - if (!PyArg_ParseTuple(extra_args, "si", &expression, &unique_id)) { - Py_DECREF(extra_args); - return NULL; - } - - xrequest->SetAttribute("expression", expression); - xrequest->SetAttribute("unique_id", unique_id); - nout << "sending " << doc << "\n" << flush; - _pipe_write << doc << flush; - */ - } else { string message = string("Unsupported request type: ") + string(request_type); PyErr_SetString(PyExc_ValueError, message.c_str()); @@ -687,12 +660,10 @@ spawn_read_thread() { //////////////////////////////////////////////////////////////////// void P3DPythonRun:: join_read_thread() { - nout << "waiting for thread\n"; _read_thread_continue = false; _pipe_read.close(); JOIN_THREAD(_read_thread); - nout << "done waiting for thread\n"; } //////////////////////////////////////////////////////////////////// @@ -703,7 +674,6 @@ join_read_thread() { //////////////////////////////////////////////////////////////////// void P3DPythonRun:: start_instance(P3DCInstance *inst, TiXmlElement *xinstance) { - nout << "starting instance " << inst << "\n"; _instances[inst->get_instance_id()] = inst; TiXmlElement *xfparams = xinstance->FirstChildElement("fparams"); @@ -861,14 +831,12 @@ terminate_session() { } _instances.clear(); - nout << "calling stop()\n"; PyObject *result = PyObject_CallMethod(_taskMgr, (char *)"stop", (char *)""); if (result == NULL) { PyErr_Print(); return; } Py_DECREF(result); - nout << "done calling stop()\n"; // The task manager is cleaned up. Let's exit immediately here, // rather than returning all the way up. This just makes it easier @@ -1045,14 +1013,12 @@ xml_to_pyobj(TiXmlElement *xvalue) { //////////////////////////////////////////////////////////////////// void P3DPythonRun:: rt_thread_run() { - nout << "thread reading.\n"; while (_read_thread_continue) { TiXmlDocument *doc = new TiXmlDocument; _pipe_read >> *doc; if (!_pipe_read || _pipe_read.eof()) { // Some error on reading. Abort. - nout << "Error on reading.\n"; _program_continue = false; return; } diff --git a/direct/src/plugin/p3dSession.cxx b/direct/src/plugin/p3dSession.cxx index bb5e7c52db..3237beb777 100644 --- a/direct/src/plugin/p3dSession.cxx +++ b/direct/src/plugin/p3dSession.cxx @@ -214,7 +214,6 @@ void P3DSession:: send_command(TiXmlDocument *command) { if (_p3dpython_running) { // Python is running. Send the command. - nout << "Sending " << *command << "\n" << flush; _pipe_write << *command << flush; delete command; } else { @@ -258,7 +257,6 @@ command_and_response(TiXmlDocument *command) { // Now block, waiting for a response to be delivered. We assume // only one thread will be waiting at a time. - nout << "Waiting for response " << response_id << "\n" << flush; _response_ready.acquire(); while (_response == NULL || _got_response_id != response_id) { if (_response != NULL) { @@ -307,8 +305,6 @@ command_and_response(TiXmlDocument *command) { _response_ready.release(); - nout << "Got response: " << *response << "\n" << flush; - return response; } @@ -358,8 +354,6 @@ xml_to_p3dobj(const TiXmlElement *xvalue) { int object_id; if (xvalue->QueryIntAttribute("object_id", &object_id) == TIXML_SUCCESS) { P3D_object *obj = (P3D_object *)object_id; - nout << "Found object " << obj << "\n" << flush; - nout << " formatted is " << *obj << "\n" << flush; return P3D_OBJECT_COPY(obj); } @@ -534,8 +528,6 @@ start_p3dpython() { } _p3dpython_running = true; - nout << "Created child process\n" << flush; - if (!_pipe_read) { nout << "unable to open read pipe\n" << flush; } @@ -597,14 +589,12 @@ join_read_thread() { //////////////////////////////////////////////////////////////////// void P3DSession:: rt_thread_run() { - nout << "session thread reading.\n" << flush; while (_read_thread_continue) { TiXmlDocument *doc = new TiXmlDocument; _pipe_read >> *doc; if (!_pipe_read || _pipe_read.eof()) { // Some error on reading. Abort. - nout << "Error on session reading.\n" << flush; rt_terminate(); return; } @@ -622,8 +612,6 @@ rt_thread_run() { //////////////////////////////////////////////////////////////////// void P3DSession:: rt_handle_request(TiXmlDocument *doc) { - nout << "Session got request: " << *doc << "\n" << flush; - TiXmlElement *xresponse = doc->FirstChildElement("response"); if (xresponse != (TiXmlElement *)NULL) { int response_id; @@ -649,7 +637,6 @@ rt_handle_request(TiXmlDocument *doc) { TiXmlElement *xrequest = doc->FirstChildElement("request"); if (xrequest != (TiXmlElement *)NULL) { - nout << "Handling request\n" << flush; int instance_id; if (xrequest->QueryIntAttribute("instance_id", &instance_id) == TIXML_SUCCESS) { // Look up the particular instance this is related to. @@ -665,7 +652,6 @@ rt_handle_request(TiXmlDocument *doc) { } RELEASE_LOCK(_instances_lock); } - nout << "done handling request\n" << flush; } delete doc; @@ -699,11 +685,7 @@ rt_make_p3d_request(TiXmlElement *xrequest) { xrequest->Attribute("unique_id", &unique_id); if (operation != NULL && xobject != NULL) { - nout << "xobject = " << *xobject << "\n" << flush; P3D_object *object = xml_to_p3dobj(xobject); - nout << "converted to " << object << "\n" << flush; - nout << "object = " << *object << "\n" << flush; - nout << "operation = " << *operation << "\n" << flush; if (strcmp(operation, "get_property") == 0 && property_name != NULL) { request = new P3D_request; request->_request_type = P3D_RT_script; @@ -737,7 +719,7 @@ rt_make_p3d_request(TiXmlElement *xrequest) { } } else { - nout << "ignoring request of type " << rtype << "\n"; + nout << "Ignoring request of type " << rtype << "\n"; } } diff --git a/direct/src/plugin_npapi/ppBrowserObject.cxx b/direct/src/plugin_npapi/ppBrowserObject.cxx index 5d72691010..896ba2a552 100644 --- a/direct/src/plugin_npapi/ppBrowserObject.cxx +++ b/direct/src/plugin_npapi/ppBrowserObject.cxx @@ -121,6 +121,12 @@ get_repr(char *buffer, int buffer_length) const { P3D_object *PPBrowserObject:: get_property(const string &property) const { NPIdentifier property_name = browser->getstringidentifier(property.c_str()); + if (!browser->hasproperty(_instance->get_npp_instance(), _npobj, + property_name)) { + // No such property. + return NULL; + } + NPVariant result; if (!browser->getproperty(_instance->get_npp_instance(), _npobj, property_name, &result)) { @@ -142,10 +148,30 @@ get_property(const string &property) const { //////////////////////////////////////////////////////////////////// bool PPBrowserObject:: set_property(const string &property, P3D_object *value) { + NPIdentifier property_name = browser->getstringidentifier(property.c_str()); + bool result; if (value != NULL) { + // Set the property. + if (P3D_OBJECT_GET_TYPE(value) != P3D_OT_null) { + NPVariant npvalue; + _instance->p3dobj_to_variant(&npvalue, value); + result = browser->setproperty(_instance->get_npp_instance(), _npobj, + property_name, &npvalue); + browser->releasevariantvalue(&npvalue); + } else { + // Actually, delete the property after all. + result = browser->removeproperty(_instance->get_npp_instance(), _npobj, + property_name); + } P3D_OBJECT_FINISH(value); + + } else { + // Delete the property. + result = browser->removeproperty(_instance->get_npp_instance(), _npobj, + property_name); } - return false; + + return result; } //////////////////////////////////////////////////////////////////// diff --git a/direct/src/plugin_npapi/ppInstance.cxx b/direct/src/plugin_npapi/ppInstance.cxx index 575c51f738..4d0793abf8 100644 --- a/direct/src/plugin_npapi/ppInstance.cxx +++ b/direct/src/plugin_npapi/ppInstance.cxx @@ -34,7 +34,6 @@ PPInstance:: PPInstance(NPMIMEType pluginType, NPP instance, uint16 mode, int16 argc, char *argn[], char *argv[], NPSavedData *saved) { - logfile << "constructing " << this << "\n" << flush; _p3d_inst = NULL; _npp_instance = instance; @@ -47,8 +46,6 @@ PPInstance(NPMIMEType pluginType, NPP instance, uint16 mode, P3D_token token; token._keyword = strdup(argn[i]); token._value = strdup(argv[i]); - logfile - << " " << i << ": " << token._keyword << " = " << token._value << "\n"; _tokens.push_back(token); } @@ -72,9 +69,6 @@ PPInstance(NPMIMEType pluginType, NPP instance, uint16 mode, //////////////////////////////////////////////////////////////////// PPInstance:: ~PPInstance() { - logfile - << "destructing PPInstance " << this << "\n"; - #ifdef _WIN32 if (_got_window) { // Restore the parent window to its own window handler. @@ -330,7 +324,6 @@ stream_as_file(NPStream *stream, const char *fname) { } } filename = fname2; - logfile << "converted filename to " << filename << "\n"; } // Here's another temporary hack. In addition to the weird filename @@ -343,7 +336,6 @@ stream_as_file(NPStream *stream, const char *fname) { // the filename to point to the source file. if (strncmp(stream->url, "file://", 7) == 0) { filename = stream->url + 7; - logfile << "converted filename again to " << filename << "\n"; } #endif // __APPLE__ @@ -353,7 +345,6 @@ stream_as_file(NPStream *stream, const char *fname) { case PPDownloadRequest::RT_contents_file: // Now we have the contents.xml file. Read this to get the // filename and md5 hash of our core API DLL. - logfile << "got contents file " << filename << "\n" << flush; if (!read_contents_file(filename)) { logfile << "Unable to read contents file\n"; // TODO: fail @@ -388,16 +379,12 @@ stream_as_file(NPStream *stream, const char *fname) { //////////////////////////////////////////////////////////////////// void PPInstance:: handle_request(P3D_request *request) { - logfile - << "handle_request: " << request << ", " << request->_request_type - << " within " << this << "\n" << flush; assert(request->_instance == _p3d_inst); bool handled = false; switch (request->_request_type) { case P3D_RT_stop: - logfile << "Got P3D_RT_stop\n"; if (_p3d_inst != NULL) { P3D_instance_finish(_p3d_inst); _p3d_inst = NULL; @@ -408,9 +395,6 @@ handle_request(P3D_request *request) { case P3D_RT_get_url: { - logfile << "Got P3D_RT_get_url: " << request->_request._get_url._url - << "\n"; - PPDownloadRequest *req = new PPDownloadRequest(PPDownloadRequest::RT_user, request->_request._get_url._unique_id); @@ -421,15 +405,11 @@ handle_request(P3D_request *request) { case P3D_RT_notify: { - logfile << "Got P3D_RT_notify: " << request->_request._notify._message - << "\n" << flush; - if (_script_object != NULL && strcmp(request->_request._notify._message, "onpythonload") == 0) { // Now that Python is running, initialize our script_object // with the proper P3D object pointer. P3D_object *obj = P3D_instance_get_panda_script_object(_p3d_inst); - logfile << "late obj = " << obj << "\n" << flush; _script_object->set_p3d_object(obj); } } @@ -477,9 +457,7 @@ handle_request_loop() { //////////////////////////////////////////////////////////////////// NPObject *PPInstance:: get_panda_script_object() { - logfile << "get_panda_script_object\n" << flush; if (_script_object != NULL) { - logfile << "returning _script_object ref = " << _script_object->referenceCount << "\n"; return _script_object; } @@ -487,14 +465,10 @@ get_panda_script_object() { if (_p3d_inst != NULL) { obj = P3D_instance_get_panda_script_object(_p3d_inst); - logfile << "obj = " << obj << "\n" << flush; } _script_object = PPPandaObject::make_new(this, obj); - logfile << "_script_object ref = " << _script_object->referenceCount << "\n"; browser->retainobject(_script_object); - logfile << "after retain, _script_object ref = " << _script_object->referenceCount << "\n"; - logfile << "ppobj = " << _script_object << "\n" << flush; return _script_object; } @@ -507,6 +481,10 @@ get_panda_script_object() { void PPInstance:: p3dobj_to_variant(NPVariant *result, const P3D_object *object) { switch (P3D_OBJECT_GET_TYPE(object)) { + case P3D_OT_null: + NULL_TO_NPVARIANT(*result); + break; + case P3D_OT_none: VOID_TO_NPVARIANT(*result); break; @@ -551,8 +529,9 @@ p3dobj_to_variant(NPVariant *result, const P3D_object *object) { //////////////////////////////////////////////////////////////////// P3D_object *PPInstance:: variant_to_p3dobj(const NPVariant *variant) { - if (NPVARIANT_IS_VOID(*variant) || - NPVARIANT_IS_NULL(*variant)) { + if (NPVARIANT_IS_NULL(*variant)) { + return P3D_new_null_object(); + } else if (NPVARIANT_IS_VOID(*variant)) { return P3D_new_none_object(); } else if (NPVARIANT_IS_BOOLEAN(*variant)) { return P3D_new_bool_object(NPVARIANT_TO_BOOLEAN(*variant)); @@ -675,7 +654,6 @@ downloaded_plugin(const string &filename) { if (_core_api_dll.quick_verify(_root_dir)) { // We downloaded and installed it successfully. Now load it. - logfile << "Successfully downloaded " << pathname << "\n"; do_load_plugin(); return; } @@ -711,7 +689,6 @@ do_load_plugin() { logfile << "Unable to launch core API in " << pathname << "\n" << flush; return; } - logfile << "loaded core API from " << pathname << "\n" << flush; create_instance(); } @@ -750,7 +727,6 @@ create_instance() { NPObject *window_object = NULL; if (browser->getvalue(_npp_instance, NPNVWindowNPObject, &window_object) == NPERR_NO_ERROR) { - logfile << "Got window_object " << window_object << "\n" << flush; PPBrowserObject *pobj = new PPBrowserObject(this, window_object); P3D_instance_set_browser_script_object(_p3d_inst, pobj); browser->releaseobject(window_object); diff --git a/direct/src/showutil/runp3d.py b/direct/src/showutil/runp3d.py index 9ac750021e..dc98ee3550 100755 --- a/direct/src/showutil/runp3d.py +++ b/direct/src/showutil/runp3d.py @@ -27,6 +27,7 @@ from direct.stdpy import file from direct.task.TaskManagerGlobal import taskMgr from direct.showbase import AppRunnerGlobal import os +import types import __builtin__ MultifileRoot = '/mf' @@ -41,10 +42,10 @@ default-model-extension .bam class ArgumentError(AttributeError): pass -class ScriptRoot: +class ScriptAttributes: """ This dummy class serves as the root object for the scripting interface. The Python code can store objects and functions here - for direct meddling by the browser's JavaScript code. """ + for direct inspection by the browser's JavaScript code. """ pass class AppRunner(DirectObject): @@ -57,15 +58,23 @@ class AppRunner(DirectObject): self.started = False self.windowPrc = None + # Store this Null instance where the application can easily + # get to it. + self.Null = Null + # This is per session. self.nextScriptId = 0 # TODO: we need one of these per instance, not per session. self.instanceId = None - self.scriptRoot = ScriptRoot() - # This will be the browser's toplevel window DOM object. - self.window = None + # The attributes of this object will be exposed as attributes + # of the plugin instance in the DOM. + self.attributes = ScriptAttributes() + + # This will be the browser's toplevel window DOM object; + # e.g. self.dom.document will be the document. + self.dom = None # This is the default requestFunc that is installed if we # never call setRequestFunc(). @@ -151,13 +160,20 @@ class AppRunner(DirectObject): if hasattr(main, 'main') and callable(main.main): main.main() - def setBrowserScriptObject(self, window): - """ Replaces self.window with the browser's toplevel DOM + def getPandaScriptObject(self): + """ Called by the browser to query the Panda instance's + toplevel scripting object, for querying properties in the + Panda instance. The attributes on this object are mapped to + the plugin instance within the DOM. """ + return self.attributes + + def setBrowserScriptObject(self, dom): + """ Called by the browser to supply the browser's toplevel DOM object, for controlling the JavaScript and the document in the same page with the Panda3D plugin. """ - self.window = window - print "setBrowserScriptObject(%s)" % (window) + self.dom = dom + print "setBrowserScriptObject(%s)" % (dom) def setP3DFilename(self, p3dFilename, tokens = [], instanceId = None): @@ -166,7 +182,7 @@ class AppRunner(DirectObject): # for this instance. self.instanceId = instanceId - # Now that we have an instanceId, we can response to queries + # Now that we have an instanceId, we can respond to queries # and such. self.sendRequest('notify', 'onpythonload') @@ -266,8 +282,6 @@ class AppRunner(DirectObject): return self.requestFunc(self.instanceId, request, args) def windowEvent(self, win): - print "Got window event in runp3d" - self.sendRequest('notify', 'onwindowopen') def scriptRequest(self, operation, object, propertyName = None, @@ -297,7 +311,6 @@ class AppRunner(DirectObject): # Now wait for the response to come in. result = self.sendRequest('wait_script_response', uniqueId) - print "result for %s.%s = %s" % (object, propertyName, result,) return result def parseSysArgs(self): @@ -332,6 +345,16 @@ class AppRunner(DirectObject): return (osFilename, tokens) +class NullObject: + """ This is a special object that is returned by the browser to + represent a NULL pointer, typically the return value for a failed + operation. It has no attributes. """ + pass + +# In fact, we normally always return this precise instance of the +# NullObject. +Null = NullObject() + class BrowserObject: """ This class provides the Python wrapper around some object that actually exists in the plugin host's namespace, e.g. a JavaScript @@ -348,25 +371,27 @@ class BrowserObject: return True def __getattr__(self, name): - """ Remaps attempts to query an attribute into the appropriate - calls to query the actual browser object under the hood. """ + """ Remaps attempts to query an attribute, as in obj.attr, + into the appropriate calls to query the actual browser object + under the hood. """ - print "__getattr_(self, %s)" % (name) - print "runner = %s" % (self.__runner) value = self.__runner.scriptRequest('get_property', self, propertyName = name) + if value is Null: + # Failed to retrieve the attribute. + raise AttributeError(name) + return value - # raise AttributeError(name) def __setattr__(self, name, value): if name in self.__dict__: self.__dict__[name] = value return - value = self.__runner.scriptRequest('set_property', self, - propertyName = name, - value = value) - if not value: + result = self.__runner.scriptRequest('set_property', self, + propertyName = name, + value = value) + if not result: raise AttributeError(name) def __delattr__(self, name): @@ -374,11 +399,50 @@ class BrowserObject: del self.__dict__[name] return - value = self.__runner.scriptRequest('del_property', self, - propertyName = name) - if not value: + result = self.__runner.scriptRequest('del_property', self, + propertyName = name) + if not result: raise AttributeError(name) + def __getitem__(self, key): + """ Remaps attempts to query an attribute, as in obj['attr'], + into the appropriate calls to query the actual browser object + under the hood. Following the JavaScript convention, we treat + obj['attr'] almost the same as obj.attr. """ + + value = self.__runner.scriptRequest('get_property', self, + propertyName = str(key)) + if value is Null: + # Failed to retrieve the property. We return IndexError + # for numeric keys so we can properly support Python's + # iterators, but we return KeyError for string keys to + # emulate mapping objects. + if isinstance(key, types.StringTypes): + raise KeyError(key) + else: + raise IndexError(key) + + return value; + + def __setitem__(self, key, value): + result = self.__runner.scriptRequest('set_property', self, + propertyName = str(key), + value = value) + if not result: + if isinstance(key, types.StringTypes): + raise KeyError(key) + else: + raise IndexError(key) + + def __delitem__(self, key): + result = self.__runner.scriptRequest('del_property', self, + propertyName = str(key)) + if not result: + if isinstance(key, types.StringTypes): + raise KeyError(key) + else: + raise IndexError(key) + if __name__ == '__main__': runner = AppRunner() runner.gotWindow = True