callouts
This commit is contained in:
parent
c415cf8dbf
commit
7127006958
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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("");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
request->_request._script._property_name = strdup(property_name);
|
||||
request->_request._script._value = NULL;
|
||||
request->_request._script._unique_id = unique_id;
|
||||
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;
|
||||
}
|
||||
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 = 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._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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
Loading…
Reference in New Issue