David Rose преди 16 години
родител
ревизия
7127006958

+ 41 - 3
direct/src/plugin/p3dInstance.cxx

@@ -266,7 +266,9 @@ get_request() {
 
 
     case P3D_RT_script:
     case P3D_RT_script:
       handle_script_request(result);
       handle_script_request(result);
-      break;
+      // Completely eat this request; don't return it to the caller.
+      finish_request(result, true);
+      return get_request();
 
 
     default:
     default:
       // Other kinds of requests don't require special handling at
       // Other kinds of requests don't require special handling at
@@ -520,8 +522,14 @@ handle_script_request(P3D_request *request) {
 
 
   case P3D_SO_set_property:
   case P3D_SO_set_property:
     {
     {
-      bool result = P3D_OBJECT_SET_PROPERTY(object, request->_request._script._property_name,
-                                            request->_request._script._value);
+      bool result;
+      if (request->_request._script._num_values == 1) {
+        result = P3D_OBJECT_SET_PROPERTY(object, request->_request._script._property_name,
+                                         request->_request._script._values[0]);
+      } else {
+        // Wrong number of values.  Error.
+        result = false;
+      }
 
 
       // Feed the result back down to the subprocess.
       // Feed the result back down to the subprocess.
       TiXmlDocument *doc = new TiXmlDocument;
       TiXmlDocument *doc = new TiXmlDocument;
@@ -565,6 +573,36 @@ handle_script_request(P3D_request *request) {
       _session->send_command(doc);
       _session->send_command(doc);
     }
     }
     break;
     break;
+
+  case P3D_SO_call:
+    {
+      P3D_object *result = 
+        P3D_OBJECT_CALL(object, request->_request._script._property_name,
+                        request->_request._script._values,
+                        request->_request._script._num_values);
+      // Reset the value count to 0 so we won't double-delete the
+      // values when the request is deleted (the above call has
+      // already deleted them).
+      request->_request._script._num_values = 0;
+
+      // Feed the result back down to the subprocess.
+      TiXmlDocument *doc = new TiXmlDocument;
+      TiXmlDeclaration *decl = new TiXmlDeclaration("1.0", "utf-8", "");
+      TiXmlElement *xcommand = new TiXmlElement("command");
+      xcommand->SetAttribute("cmd", "script_response");
+      xcommand->SetAttribute("unique_id", unique_id);
+      
+      doc->LinkEndChild(decl);
+      doc->LinkEndChild(xcommand);
+
+      if (result != NULL) {
+        xcommand->LinkEndChild(_session->p3dobj_to_xml(result));
+        P3D_OBJECT_FINISH(result);
+      }
+      
+      _session->send_command(doc);
+    }
+    break;
   }
   }
 }
 }
 
 

+ 24 - 9
direct/src/plugin/p3dPythonRun.cxx

@@ -474,6 +474,7 @@ task_check_comm(GenericAsyncTask *task, void *user_data) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 TiXmlDocument *P3DPythonRun::
 TiXmlDocument *P3DPythonRun::
 wait_script_response(int response_id) {
 wait_script_response(int response_id) {
+  nout << "Waiting script_response " << response_id << "\n";
   while (true) {
   while (true) {
     ACQUIRE_LOCK(_commands_lock);
     ACQUIRE_LOCK(_commands_lock);
     
     
@@ -491,7 +492,7 @@ wait_script_response(int response_id) {
               // This is the response we were waiting for.
               // This is the response we were waiting for.
               _commands.erase(ci);
               _commands.erase(ci);
               RELEASE_LOCK(_commands_lock);
               RELEASE_LOCK(_commands_lock);
-              nout << "received: " << *doc << "\n" << flush;
+              nout << "received script_response: " << *doc << "\n" << flush;
               return doc;
               return doc;
             }
             }
           }
           }
@@ -525,6 +526,7 @@ wait_script_response(int response_id) {
     // process the input and append it to the queue.
     // process the input and append it to the queue.
     Thread::force_yield();
     Thread::force_yield();
   }
   }
+  assert(false);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -549,11 +551,11 @@ py_request_func(PyObject *args) {
     // on the wire.
     // on the wire.
     int response_id;
     int response_id;
     if (!PyArg_ParseTuple(extra_args, "i", &response_id)) {
     if (!PyArg_ParseTuple(extra_args, "i", &response_id)) {
-      Py_DECREF(extra_args);
       return NULL;
       return NULL;
     }
     }
 
 
     TiXmlDocument *doc = wait_script_response(response_id);
     TiXmlDocument *doc = wait_script_response(response_id);
+    assert(doc != NULL);
     TiXmlElement *xcommand = doc->FirstChildElement("command");
     TiXmlElement *xcommand = doc->FirstChildElement("command");
     assert(xcommand != NULL);
     assert(xcommand != NULL);
     TiXmlElement *xvalue = xcommand->FirstChildElement("value");
     TiXmlElement *xvalue = xcommand->FirstChildElement("value");
@@ -568,7 +570,6 @@ py_request_func(PyObject *args) {
     }
     }
 
 
     delete doc;
     delete doc;
-    Py_DECREF(extra_args);
     return value;
     return value;
   }
   }
 
 
@@ -584,7 +585,6 @@ py_request_func(PyObject *args) {
     // A general notification to be sent directly to the instance.
     // A general notification to be sent directly to the instance.
     const char *message;
     const char *message;
     if (!PyArg_ParseTuple(extra_args, "s", &message)) {
     if (!PyArg_ParseTuple(extra_args, "s", &message)) {
-      Py_DECREF(extra_args);
       return NULL;
       return NULL;
     }
     }
 
 
@@ -601,7 +601,6 @@ py_request_func(PyObject *args) {
     int unique_id;
     int unique_id;
     if (!PyArg_ParseTuple(extra_args, "sOsOi", 
     if (!PyArg_ParseTuple(extra_args, "sOsOi", 
                           &operation, &object, &property_name, &value, &unique_id)) {
                           &operation, &object, &property_name, &value, &unique_id)) {
-      Py_DECREF(extra_args);
       return NULL;
       return NULL;
     }
     }
 
 
@@ -611,8 +610,26 @@ py_request_func(PyObject *args) {
     TiXmlElement *xobject = pyobj_to_xml(object);
     TiXmlElement *xobject = pyobj_to_xml(object);
     xobject->SetValue("object");
     xobject->SetValue("object");
     xrequest->LinkEndChild(xobject);
     xrequest->LinkEndChild(xobject);
-    TiXmlElement *xvalue = pyobj_to_xml(value);
-    xrequest->LinkEndChild(xvalue);
+
+    if (strcmp(operation, "call") == 0 && PySequence_Check(value)) {
+      // A special case: operation "call" receives a tuple of
+      // parameters; unpack the tuple for the XML.
+      Py_ssize_t length = PySequence_Length(value);
+      for (Py_ssize_t i = 0; i < length; ++i) {
+        PyObject *p = PySequence_GetItem(value, i);
+        if (p != NULL) {
+          TiXmlElement *xvalue = pyobj_to_xml(p);
+          xrequest->LinkEndChild(xvalue);
+          Py_DECREF(p);
+        }
+      }
+      
+    } else {
+      // Other kinds of operations receive only a single parameter, if
+      // any.
+      TiXmlElement *xvalue = pyobj_to_xml(value);
+      xrequest->LinkEndChild(xvalue);
+    }
 
 
     nout << "sent: " << doc << "\n" << flush;
     nout << "sent: " << doc << "\n" << flush;
     _pipe_write << doc << flush;
     _pipe_write << doc << flush;
@@ -620,11 +637,9 @@ py_request_func(PyObject *args) {
   } else {
   } else {
     string message = string("Unsupported request type: ") + string(request_type);
     string message = string("Unsupported request type: ") + string(request_type);
     PyErr_SetString(PyExc_ValueError, message.c_str());
     PyErr_SetString(PyExc_ValueError, message.c_str());
-    Py_DECREF(extra_args);
     return NULL;
     return NULL;
   }
   }
 
 
-  Py_DECREF(extra_args);
   return Py_BuildValue("");
   return Py_BuildValue("");
 }
 }
 
 

+ 42 - 29
direct/src/plugin/p3dSession.cxx

@@ -684,41 +684,54 @@ rt_make_p3d_request(TiXmlElement *xrequest) {
       const char *operation = xrequest->Attribute("operation");
       const char *operation = xrequest->Attribute("operation");
       TiXmlElement *xobject = xrequest->FirstChildElement("object");
       TiXmlElement *xobject = xrequest->FirstChildElement("object");
       const char *property_name = xrequest->Attribute("property_name");
       const char *property_name = xrequest->Attribute("property_name");
-      TiXmlElement *xvalue = xrequest->FirstChildElement("value");
       int unique_id = 0;
       int unique_id = 0;
       xrequest->Attribute("unique_id", &unique_id);
       xrequest->Attribute("unique_id", &unique_id);
 
 
       if (operation != NULL && xobject != NULL) {
       if (operation != NULL && xobject != NULL) {
-        P3D_object *object = xml_to_p3dobj(xobject);
-        if (strcmp(operation, "get_property") == 0 && property_name != NULL) {
-          request = new P3D_request;
-          request->_request_type = P3D_RT_script;
-          request->_request._script._object = object;
-          request->_request._script._op = P3D_SO_get_property;
-          request->_request._script._property_name = strdup(property_name);
-          request->_request._script._value = NULL;
-          request->_request._script._unique_id = unique_id;
-        } else if (strcmp(operation, "set_property") == 0 && property_name != NULL && xvalue != NULL) {
-          request = new P3D_request;
-          request->_request_type = P3D_RT_script;
-          request->_request._script._object = object;
-          request->_request._script._op = P3D_SO_set_property;
-          request->_request._script._property_name = strdup(property_name);
-          request->_request._script._value = xml_to_p3dobj(xvalue);
-          request->_request._script._unique_id = unique_id;
-        } else if (strcmp(operation, "del_property") == 0 && property_name != NULL) {
-          request = new P3D_request;
-          request->_request_type = P3D_RT_script;
-          request->_request._script._object = object;
-          request->_request._script._op = P3D_SO_del_property;
+        P3D_script_operation op;
+        if (strcmp(operation, "get_property") == 0) {
+          op = P3D_SO_get_property;
+        } else if (strcmp(operation, "set_property") == 0) {
+          op = P3D_SO_set_property;
+        } else if (strcmp(operation, "del_property") == 0) {
+          op = P3D_SO_del_property;
+        } else if (strcmp(operation, "call") == 0) {
+          op = P3D_SO_call;
+        } else {
+          // An unexpected operation.
+          return NULL;
+        }
+
+        request = new P3D_request;
+        request->_request_type = P3D_RT_script;
+        request->_request._script._op = op;
+        request->_request._script._object = xml_to_p3dobj(xobject);
+        request->_request._script._property_name = NULL;
+        if (property_name != NULL) {
           request->_request._script._property_name = strdup(property_name);
           request->_request._script._property_name = strdup(property_name);
-          request->_request._script._value = NULL;
-          request->_request._script._unique_id = unique_id;
         }
         }
-        if (request == NULL) {
-          // If we haven't dispatched a request yet, we didn't use the
-          // object, so delete it.
-          P3D_OBJECT_FINISH(object);
+        request->_request._script._unique_id = unique_id;
+        
+        // Fill in the value(s).
+        vector<P3D_object *> values;
+        TiXmlElement *xvalue = xrequest->FirstChildElement("value");
+        while (xvalue != NULL) {
+          P3D_object *value = xml_to_p3dobj(xvalue);
+          values.push_back(value);
+          xvalue = xvalue->NextSiblingElement("value");
+        }
+
+        if (values.empty()) {
+          // No values.
+          request->_request._script._values = NULL;
+          request->_request._script._num_values = 0;
+        } else {
+          // Some values.
+          int num_values = (int)values.size();
+          P3D_object **valuesp = new P3D_object *[num_values];
+          memcpy(valuesp, &values[0], num_values * sizeof(P3D_object *));
+          request->_request._script._values = valuesp;
+          request->_request._script._num_values = num_values;
         }
         }
       }          
       }          
 
 

+ 2 - 1
direct/src/plugin/p3d_plugin.h

@@ -609,7 +609,8 @@ typedef struct {
   P3D_object *_object;
   P3D_object *_object;
   P3D_script_operation _op;
   P3D_script_operation _op;
   const char *_property_name;
   const char *_property_name;
-  P3D_object *_value;
+  P3D_object **_values;
+  int _num_values;
   int _unique_id;
   int _unique_id;
 } P3D_request_script;
 } P3D_request_script;
 
 

+ 31 - 2
direct/src/plugin_npapi/ppBrowserObject.cxx

@@ -184,10 +184,39 @@ set_property(const string &property, P3D_object *value) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 P3D_object *PPBrowserObject::
 P3D_object *PPBrowserObject::
 call(const string &method_name, P3D_object *params[], int num_params) const {
 call(const string &method_name, P3D_object *params[], int num_params) const {
+  // First, convert all of the parameters.
+  NPVariant *npparams = new NPVariant[num_params];
   for (int i = 0; i < num_params; ++i) {
   for (int i = 0; i < num_params; ++i) {
-    P3D_OBJECT_FINISH(params[i]);
+    _instance->p3dobj_to_variant(&npparams[i], params[i]);
   }
   }
-  return NULL;
+
+  NPVariant result;
+  if (method_name.empty()) {
+    // Call the default method.
+    if (!browser->invokeDefault(_instance->get_npp_instance(), _npobj,
+                                npparams, num_params, &result)) {
+      // Failed to invoke.
+      logfile << "invoke failed\n" << flush;
+      delete[] npparams;
+      return NULL;
+    }
+  } else {
+    // Call the named method.
+
+    NPIdentifier method_id = browser->getstringidentifier(method_name.c_str());
+    if (!browser->invoke(_instance->get_npp_instance(), _npobj, method_id,
+                         npparams, num_params, &result)) {
+      // Failed to invoke.
+      delete[] npparams;
+      return NULL;
+    }
+  }
+
+  logfile << "invoke succeeded\n" << flush;
+
+  P3D_object *object = _instance->variant_to_p3dobj(&result);
+  browser->releasevariantvalue(&result);
+  return object;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

+ 1 - 1
direct/src/plugin_npapi/startup.cxx

@@ -313,7 +313,7 @@ NPP_Print(NPP instance, NPPrint *platformPrint) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 int16
 int16
 NPP_HandleEvent(NPP instance, void *event) {
 NPP_HandleEvent(NPP instance, void *event) {
-  logfile << "HandleEvent\n" << flush;
+  //  logfile << "HandleEvent\n" << flush;
 
 
   // Here's a fine opportunity to check for new requests.
   // Here's a fine opportunity to check for new requests.
   PPInstance::handle_request_loop();
   PPInstance::handle_request_loop();

+ 0 - 27
direct/src/plugin_standalone/panda3d.cxx

@@ -405,33 +405,6 @@ handle_request(P3D_request *request) {
     cerr << "Got P3D_RT_notify: " << request->_request._notify._message
     cerr << "Got P3D_RT_notify: " << request->_request._notify._message
          << "\n";
          << "\n";
     // Ignore notifications.
     // Ignore notifications.
-    
-    /*
-    {
-      // Temporary.
-      P3D_object *obj = P3D_instance_get_panda_script_object(request->_instance);
-      cerr << "script_object is " << obj << "\n";
-      if (obj != NULL) {
-        if (P3D_OBJECT_SET_PROPERTY(obj, "foo", P3D_new_int_object(1))) {
-          cerr << "set_property succeeded\n";
-          P3D_object *prop = P3D_OBJECT_GET_PROPERTY(obj, "foo");
-          cerr << "get_property returned " << prop << "\n";
-          if (prop != NULL) {
-            int size = P3D_OBJECT_GET_STRING(prop, NULL, 0) + 1;
-            char *buffer = new char[size];
-            P3D_OBJECT_GET_STRING(prop, buffer, size);
-            cerr << "  property is " << buffer << "\n";
-            delete buffer;
-            P3D_OBJECT_FINISH(prop);
-          }
-        } else {
-          cerr << "set_property failed\n";
-        }
-        P3D_OBJECT_FINISH(obj);
-      }
-    }
-    */
-
     break;
     break;
 
 
   default:
   default:

+ 34 - 2
direct/src/showutil/runp3d.py

@@ -284,7 +284,7 @@ class AppRunner(DirectObject):
     def windowEvent(self, win):
     def windowEvent(self, win):
         self.sendRequest('notify', 'onwindowopen')
         self.sendRequest('notify', 'onwindowopen')
 
 
-    def scriptRequest(self, operation, object, propertyName = None,
+    def scriptRequest(self, operation, object, propertyName = '',
                       value = None):
                       value = None):
         """ Issues a new script request to the browser.  This queries
         """ Issues a new script request to the browser.  This queries
         or modifies one of the browser's DOM properties.  This method
         or modifies one of the browser's DOM properties.  This method
@@ -364,12 +364,37 @@ class BrowserObject:
         self.__dict__['_BrowserObject__runner'] = runner
         self.__dict__['_BrowserObject__runner'] = runner
         self.__dict__['_BrowserObject__objectId'] = objectId
         self.__dict__['_BrowserObject__objectId'] = objectId
 
 
+        # This element is filled in by __getattr__; it connects
+        # the object to its parent.
+        self.__dict__['_BrowserObject__boundMethod'] = (None, None)
+
     def __str__(self):
     def __str__(self):
-        return "BrowserObject(%s)" % (self.__objectId)
+        parentObj, attribName = self.__boundMethod
+        if parentObj:
+            # Format it from its parent.
+            return "%s.%s" % (parentObj, attribName)
+        else:
+            # Format it directly.
+            return "BrowserObject(%s)" % (self.__objectId)
 
 
     def __nonzero__(self):
     def __nonzero__(self):
         return True
         return True
 
 
+    def __call__(self, *args):
+        parentObj, attribName = self.__boundMethod
+        if parentObj:
+            # Call it as a method.
+            result = self.__runner.scriptRequest('call', parentObj, propertyName = attribName, value = args)
+        else:
+            # Call it as a plain function.
+            result = self.__runner.scriptRequest('call', self, value = args)
+
+        if result is Null:
+            # Could not call the method.
+            raise TypeError
+
+        return result
+
     def __getattr__(self, name):
     def __getattr__(self, name):
         """ Remaps attempts to query an attribute, as in obj.attr,
         """ Remaps attempts to query an attribute, as in obj.attr,
         into the appropriate calls to query the actual browser object
         into the appropriate calls to query the actual browser object
@@ -381,6 +406,13 @@ class BrowserObject:
             # Failed to retrieve the attribute.
             # Failed to retrieve the attribute.
             raise AttributeError(name)
             raise AttributeError(name)
 
 
+        if isinstance(value, BrowserObject):
+            # Fill in the parent object association, so __call__ can
+            # properly call a method.  (Javascript needs to know the
+            # method container at the time of the call, and doesn't
+            # store it on the function object.)
+            value.__dict__['_BrowserObject__boundMethod'] = (self, name)
+
         return value
         return value
 
 
     def __setattr__(self, name, value):
     def __setattr__(self, name, value):