David Rose %!s(int64=16) %!d(string=hai) anos
pai
achega
7127006958

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

@@ -266,7 +266,9 @@ get_request() {
 
     case P3D_RT_script:
       handle_script_request(result);
-      break;
+      // Completely eat this request; don't return it to the caller.
+      finish_request(result, true);
+      return get_request();
 
     default:
       // 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:
     {
-      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.
       TiXmlDocument *doc = new TiXmlDocument;
@@ -565,6 +573,36 @@ handle_script_request(P3D_request *request) {
       _session->send_command(doc);
     }
     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::
 wait_script_response(int response_id) {
+  nout << "Waiting script_response " << response_id << "\n";
   while (true) {
     ACQUIRE_LOCK(_commands_lock);
     
@@ -491,7 +492,7 @@ wait_script_response(int response_id) {
               // This is the response we were waiting for.
               _commands.erase(ci);
               RELEASE_LOCK(_commands_lock);
-              nout << "received: " << *doc << "\n" << flush;
+              nout << "received script_response: " << *doc << "\n" << flush;
               return doc;
             }
           }
@@ -525,6 +526,7 @@ wait_script_response(int response_id) {
     // process the input and append it to the queue.
     Thread::force_yield();
   }
+  assert(false);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -549,11 +551,11 @@ py_request_func(PyObject *args) {
     // on the wire.
     int response_id;
     if (!PyArg_ParseTuple(extra_args, "i", &response_id)) {
-      Py_DECREF(extra_args);
       return NULL;
     }
 
     TiXmlDocument *doc = wait_script_response(response_id);
+    assert(doc != NULL);
     TiXmlElement *xcommand = doc->FirstChildElement("command");
     assert(xcommand != NULL);
     TiXmlElement *xvalue = xcommand->FirstChildElement("value");
@@ -568,7 +570,6 @@ py_request_func(PyObject *args) {
     }
 
     delete doc;
-    Py_DECREF(extra_args);
     return value;
   }
 
@@ -584,7 +585,6 @@ py_request_func(PyObject *args) {
     // A general notification to be sent directly to the instance.
     const char *message;
     if (!PyArg_ParseTuple(extra_args, "s", &message)) {
-      Py_DECREF(extra_args);
       return NULL;
     }
 
@@ -601,7 +601,6 @@ py_request_func(PyObject *args) {
     int unique_id;
     if (!PyArg_ParseTuple(extra_args, "sOsOi", 
                           &operation, &object, &property_name, &value, &unique_id)) {
-      Py_DECREF(extra_args);
       return NULL;
     }
 
@@ -611,8 +610,26 @@ py_request_func(PyObject *args) {
     TiXmlElement *xobject = pyobj_to_xml(object);
     xobject->SetValue("object");
     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;
     _pipe_write << doc << flush;
@@ -620,11 +637,9 @@ py_request_func(PyObject *args) {
   } else {
     string message = string("Unsupported request type: ") + string(request_type);
     PyErr_SetString(PyExc_ValueError, message.c_str());
-    Py_DECREF(extra_args);
     return NULL;
   }
 
-  Py_DECREF(extra_args);
   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");
       TiXmlElement *xobject = xrequest->FirstChildElement("object");
       const char *property_name = xrequest->Attribute("property_name");
-      TiXmlElement *xvalue = xrequest->FirstChildElement("value");
       int unique_id = 0;
       xrequest->Attribute("unique_id", &unique_id);
 
       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._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_script_operation _op;
   const char *_property_name;
-  P3D_object *_value;
+  P3D_object **_values;
+  int _num_values;
   int _unique_id;
 } 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::
 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) {
-    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
 NPP_HandleEvent(NPP instance, void *event) {
-  logfile << "HandleEvent\n" << flush;
+  //  logfile << "HandleEvent\n" << flush;
 
   // Here's a fine opportunity to check for new requests.
   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
          << "\n";
     // 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;
 
   default:

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

@@ -284,7 +284,7 @@ class AppRunner(DirectObject):
     def windowEvent(self, win):
         self.sendRequest('notify', 'onwindowopen')
 
-    def scriptRequest(self, operation, object, propertyName = None,
+    def scriptRequest(self, operation, object, propertyName = '',
                       value = None):
         """ Issues a new script request to the browser.  This queries
         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__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):
-        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):
         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):
         """ Remaps attempts to query an attribute, as in obj.attr,
         into the appropriate calls to query the actual browser object
@@ -381,6 +406,13 @@ class BrowserObject:
             # Failed to retrieve the attribute.
             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
 
     def __setattr__(self, name, value):