much better object model
This commit is contained in:
parent
98177dc123
commit
4d2ffd8e77
|
|
@ -40,6 +40,7 @@
|
|||
p3dObject.h p3dObject.I \
|
||||
p3dPackage.h p3dPackage.I \
|
||||
p3dPythonObject.h \
|
||||
p3dReferenceCount.h p3dReferenceCount.I \
|
||||
p3dSession.h p3dSession.I \
|
||||
p3dSplashWindow.h p3dSplashWindow.I \
|
||||
p3dStringObject.h \
|
||||
|
|
@ -64,6 +65,7 @@
|
|||
p3dObject.cxx \
|
||||
p3dPackage.cxx \
|
||||
p3dPythonObject.cxx \
|
||||
p3dReferenceCount.cxx \
|
||||
p3dSession.cxx \
|
||||
p3dSplashWindow.cxx \
|
||||
p3dStringObject.cxx \
|
||||
|
|
|
|||
|
|
@ -71,6 +71,9 @@ P3DInstance(P3D_request_ready_func *func, void *user_data) :
|
|||
////////////////////////////////////////////////////////////////////
|
||||
P3DInstance::
|
||||
~P3DInstance() {
|
||||
// TODO: maybe this should be a reference-counted object, so we
|
||||
// don't delete it too soon.
|
||||
|
||||
assert(_session == NULL);
|
||||
|
||||
P3D_OBJECT_XDECREF(_browser_script_object);
|
||||
|
|
@ -90,7 +93,8 @@ P3DInstance::
|
|||
_splash_window = NULL;
|
||||
}
|
||||
|
||||
// TODO: empty _pending_requests queue and _downloads map.
|
||||
// TODO: empty _raw_requests and _baked_requests queues, and
|
||||
// _downloads map.
|
||||
|
||||
// TODO: Is it possible for someone to delete an instance while a
|
||||
// download is still running? Who will crash when this happens?
|
||||
|
|
@ -239,10 +243,7 @@ set_browser_script_object(P3D_object *browser_script_object) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
bool P3DInstance::
|
||||
has_request() {
|
||||
ACQUIRE_LOCK(_request_lock);
|
||||
bool any_requests = !_pending_requests.empty();
|
||||
RELEASE_LOCK(_request_lock);
|
||||
return any_requests;
|
||||
return _request_pending;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -256,52 +257,105 @@ has_request() {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
P3D_request *P3DInstance::
|
||||
get_request() {
|
||||
P3D_request *result = NULL;
|
||||
ACQUIRE_LOCK(_request_lock);
|
||||
if (!_pending_requests.empty()) {
|
||||
result = _pending_requests.front();
|
||||
_pending_requests.pop_front();
|
||||
_request_pending = !_pending_requests.empty();
|
||||
}
|
||||
RELEASE_LOCK(_request_lock);
|
||||
|
||||
if (result != NULL) {
|
||||
switch (result->_request_type) {
|
||||
case P3D_RT_notify:
|
||||
handle_notify_request(result);
|
||||
break;
|
||||
|
||||
case P3D_RT_script:
|
||||
handle_script_request(result);
|
||||
// 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
|
||||
// this level; pass it up unmolested.
|
||||
break;
|
||||
}
|
||||
bake_requests();
|
||||
if (_baked_requests.empty()) {
|
||||
// No requests ready.
|
||||
_request_pending = false;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return result;
|
||||
P3D_request *request = _baked_requests.front();
|
||||
_baked_requests.pop_front();
|
||||
_request_pending = !_baked_requests.empty();
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DInstance::add_request
|
||||
// Function: P3DInstance::bake_requests
|
||||
// Access: Public
|
||||
// Description: May be called in any thread to add a new P3D_request
|
||||
// to the pending_request queue for this instance.
|
||||
// Description: Copies requests from the _raw_requests queue, which
|
||||
// is built up in one or more sub-threads, into the
|
||||
// _baked_requests queue, which is publicly presented
|
||||
// to the browser. Along the way, some requests (like
|
||||
// script requests) are handled immediately.
|
||||
//
|
||||
// At the end of this call, _baked_requests will contain
|
||||
// the current set of requests pending for the browser.
|
||||
//
|
||||
// This method should only be called in the main thread.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void P3DInstance::
|
||||
add_request(P3D_request *request) {
|
||||
request->_instance = this;
|
||||
bake_requests() {
|
||||
while (true) {
|
||||
// Get the latest request from the read thread.
|
||||
TiXmlDocument *doc = NULL;
|
||||
ACQUIRE_LOCK(_request_lock);
|
||||
if (!_raw_requests.empty()) {
|
||||
doc = _raw_requests.front();
|
||||
_raw_requests.pop_front();
|
||||
}
|
||||
RELEASE_LOCK(_request_lock);
|
||||
|
||||
if (doc == NULL) {
|
||||
// No more requests to process right now.
|
||||
return;
|
||||
}
|
||||
nout << "received: " << *doc << "\n" << flush;
|
||||
|
||||
// Now we've got a request in XML form; convert it to P3D_request
|
||||
// form.
|
||||
TiXmlElement *xrequest = doc->FirstChildElement("request");
|
||||
assert(xrequest != (TiXmlElement *)NULL);
|
||||
P3D_request *request = make_p3d_request(xrequest);
|
||||
delete doc;
|
||||
|
||||
if (request != NULL) {
|
||||
_baked_requests.push_back(request);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DInstance::add_raw_request
|
||||
// Access: Public
|
||||
// Description: May be called in any thread to add a new XML request
|
||||
// to the pending_request queue for this instance. The
|
||||
// XML document will be deleted when the request is
|
||||
// eventually handled.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void P3DInstance::
|
||||
add_raw_request(TiXmlDocument *doc) {
|
||||
ACQUIRE_LOCK(_request_lock);
|
||||
_pending_requests.push_back(request);
|
||||
_raw_requests.push_back(doc);
|
||||
_request_pending = true;
|
||||
RELEASE_LOCK(_request_lock);
|
||||
|
||||
// We don't decode the XML yet, since we might be running in any
|
||||
// thread here. We'll decode it in the main thread, where it's
|
||||
// safe.
|
||||
|
||||
// Tell the world we've got a new request.
|
||||
P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
|
||||
inst_mgr->signal_request_ready(this);
|
||||
_session->signal_request_ready(this);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DInstance::add_baked_request
|
||||
// Access: Public
|
||||
// Description: May be called in the main thread only to add a new
|
||||
// request to the baked_request queue. This request
|
||||
// queue is directly passed on the browser without
|
||||
// further processing at this level.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void P3DInstance::
|
||||
add_baked_request(P3D_request *request) {
|
||||
request->_instance = this;
|
||||
|
||||
_baked_requests.push_back(request);
|
||||
_request_pending = true;
|
||||
|
||||
// Tell the world we've got a new request.
|
||||
P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
|
||||
inst_mgr->signal_request_ready(this);
|
||||
|
|
@ -335,18 +389,6 @@ finish_request(P3D_request *request, bool handled) {
|
|||
case P3D_RT_notify:
|
||||
free((char *)request->_request._notify._message);
|
||||
break;
|
||||
|
||||
case P3D_RT_script:
|
||||
{
|
||||
P3D_OBJECT_DECREF(request->_request._script._object);
|
||||
if (request->_request._script._property_name != NULL) {
|
||||
free((char *)request->_request._script._property_name);
|
||||
}
|
||||
for (int i = 0; i < request->_request._script._num_values; ++i) {
|
||||
P3D_OBJECT_DECREF(request->_request._script._values[i]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
delete request;
|
||||
|
|
@ -430,7 +472,7 @@ start_download(P3DDownload *download) {
|
|||
request->_request._get_url._url = strdup(download->get_url().c_str());
|
||||
request->_request._get_url._unique_id = download_id;
|
||||
|
||||
add_request(request);
|
||||
add_baked_request(request);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -446,7 +488,7 @@ request_stop() {
|
|||
_requested_stop = true;
|
||||
P3D_request *request = new P3D_request;
|
||||
request->_request_type = P3D_RT_stop;
|
||||
add_request(request);
|
||||
add_baked_request(request);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -497,6 +539,93 @@ send_browser_script_object() {
|
|||
_session->send_command(doc);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DInstance::make_p3d_request
|
||||
// Access: Private
|
||||
// Description: Creates a new P3D_request structure from the XML.
|
||||
// Returns NULL if no request is needed.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
P3D_request *P3DInstance::
|
||||
make_p3d_request(TiXmlElement *xrequest) {
|
||||
P3D_request *request = NULL;
|
||||
|
||||
const char *rtype = xrequest->Attribute("rtype");
|
||||
if (rtype != NULL) {
|
||||
if (strcmp(rtype, "notify") == 0) {
|
||||
const char *message = xrequest->Attribute("message");
|
||||
if (message != NULL) {
|
||||
request = new P3D_request;
|
||||
request->_request_type = P3D_RT_notify;
|
||||
request->_request._notify._message = strdup(message);
|
||||
}
|
||||
|
||||
} else if (strcmp(rtype, "script") == 0) {
|
||||
// We don't actually build a P3D_request for a script request;
|
||||
// we always just handle it immediately.
|
||||
const char *operation = xrequest->Attribute("operation");
|
||||
TiXmlElement *xobject = xrequest->FirstChildElement("object");
|
||||
const char *property_name = xrequest->Attribute("property_name");
|
||||
int needs_response = 0;
|
||||
xrequest->Attribute("needs_response", &needs_response);
|
||||
int unique_id = 0;
|
||||
xrequest->Attribute("unique_id", &unique_id);
|
||||
|
||||
vector<P3D_object *> values;
|
||||
TiXmlElement *xvalue = xrequest->FirstChildElement("value");
|
||||
while (xvalue != NULL) {
|
||||
P3D_object *value = _session->xml_to_p3dobj(xvalue);
|
||||
values.push_back(value);
|
||||
xvalue = xvalue->NextSiblingElement("value");
|
||||
}
|
||||
|
||||
P3D_object **values_ptr = NULL;
|
||||
if (!values.empty()) {
|
||||
values_ptr = &values[0];
|
||||
}
|
||||
|
||||
if (operation != NULL && xobject != NULL) {
|
||||
P3D_object *object = _session->xml_to_p3dobj(xobject);
|
||||
|
||||
if (property_name == NULL) {
|
||||
property_name = "";
|
||||
}
|
||||
|
||||
handle_script_request(operation, object, property_name,
|
||||
values_ptr, values.size(),
|
||||
(needs_response != 0), unique_id);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < values.size(); ++i) {
|
||||
P3D_OBJECT_DECREF(values[i]);
|
||||
}
|
||||
|
||||
} else if (strcmp(rtype, "notify") == 0) {
|
||||
const char *message = xrequest->Attribute("message");
|
||||
if (message != NULL) {
|
||||
request = new P3D_request;
|
||||
request->_request_type = P3D_RT_notify;
|
||||
request->_request._notify._message = strdup(message);
|
||||
handle_notify_request(message);
|
||||
}
|
||||
|
||||
} else if (strcmp(rtype, "drop_p3dobj") == 0) {
|
||||
int object_id;
|
||||
if (xrequest->QueryIntAttribute("object_id", &object_id) == TIXML_SUCCESS) {
|
||||
// We no longer need to keep this reference.
|
||||
_session->drop_p3dobj(object_id);
|
||||
}
|
||||
|
||||
} else {
|
||||
nout << "Ignoring request of type " << rtype << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
if (request != NULL) {
|
||||
request->_instance = this;
|
||||
}
|
||||
return request;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DInstance::handle_notify_request
|
||||
// Access: Private
|
||||
|
|
@ -504,13 +633,10 @@ send_browser_script_object() {
|
|||
// received from the subprocess.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void P3DInstance::
|
||||
handle_notify_request(P3D_request *request) {
|
||||
assert(request->_request_type == P3D_RT_notify);
|
||||
|
||||
handle_notify_request(const string &message) {
|
||||
// We look for certain notify events that have particular meaning
|
||||
// to this instance.
|
||||
const char *message = request->_request._notify._message;
|
||||
if (strcmp(message, "onwindowopen") == 0) {
|
||||
if (message == "onwindowopen") {
|
||||
// The process told us that it just succesfully opened its
|
||||
// window. Tear down the splash window.
|
||||
_instance_window_opened = true;
|
||||
|
|
@ -528,172 +654,87 @@ handle_notify_request(P3D_request *request) {
|
|||
// received from the subprocess.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void P3DInstance::
|
||||
handle_script_request(P3D_request *request) {
|
||||
assert(request->_request_type == P3D_RT_script);
|
||||
handle_script_request(const string &operation, P3D_object *object,
|
||||
const string &property_name,
|
||||
P3D_object *values[], int num_values,
|
||||
bool needs_response, int unique_id) {
|
||||
|
||||
P3D_object *object = request->_request._script._object;
|
||||
bool needs_response = request->_request._script._needs_response;
|
||||
int unique_id = request->_request._script._unique_id;
|
||||
switch (request->_request._script._op) {
|
||||
case P3D_SO_get_property:
|
||||
{
|
||||
P3D_object *result = P3D_OBJECT_GET_PROPERTY(object, request->_request._script._property_name);
|
||||
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);
|
||||
|
||||
// We've got the property value; feed it 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_DECREF(result);
|
||||
}
|
||||
if (operation == "get_property") {
|
||||
P3D_object *result = P3D_OBJECT_GET_PROPERTY(object, property_name.c_str());
|
||||
|
||||
if (needs_response) {
|
||||
_session->send_command(doc);
|
||||
} else {
|
||||
delete doc;
|
||||
}
|
||||
// We've got the property value; feed it back down to the
|
||||
// subprocess.
|
||||
|
||||
if (result != NULL) {
|
||||
xcommand->LinkEndChild(_session->p3dobj_to_xml(result));
|
||||
P3D_OBJECT_DECREF(result);
|
||||
}
|
||||
break;
|
||||
|
||||
case P3D_SO_set_property:
|
||||
{
|
||||
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;
|
||||
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);
|
||||
|
||||
TiXmlElement *xvalue = new TiXmlElement("value");
|
||||
xvalue->SetAttribute("type", "bool");
|
||||
xvalue->SetAttribute("value", (int)result);
|
||||
xcommand->LinkEndChild(xvalue);
|
||||
|
||||
if (needs_response) {
|
||||
_session->send_command(doc);
|
||||
} else {
|
||||
delete doc;
|
||||
}
|
||||
} else if (operation == "set_property") {
|
||||
bool result;
|
||||
if (num_values == 1) {
|
||||
result = P3D_OBJECT_SET_PROPERTY(object, property_name.c_str(), values[0]);
|
||||
} else {
|
||||
// Wrong number of values. Error.
|
||||
result = false;
|
||||
}
|
||||
break;
|
||||
|
||||
TiXmlElement *xvalue = new TiXmlElement("value");
|
||||
xvalue->SetAttribute("type", "bool");
|
||||
xvalue->SetAttribute("value", (int)result);
|
||||
xcommand->LinkEndChild(xvalue);
|
||||
|
||||
case P3D_SO_del_property:
|
||||
{
|
||||
bool result = P3D_OBJECT_SET_PROPERTY(object, request->_request._script._property_name,
|
||||
NULL);
|
||||
} else if (operation == "del_property") {
|
||||
bool result = P3D_OBJECT_SET_PROPERTY(object, property_name.c_str(), NULL);
|
||||
|
||||
TiXmlElement *xvalue = new TiXmlElement("value");
|
||||
xvalue->SetAttribute("type", "bool");
|
||||
xvalue->SetAttribute("value", (int)result);
|
||||
xcommand->LinkEndChild(xvalue);
|
||||
|
||||
// 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);
|
||||
|
||||
TiXmlElement *xvalue = new TiXmlElement("value");
|
||||
xvalue->SetAttribute("type", "bool");
|
||||
xvalue->SetAttribute("value", (int)result);
|
||||
xcommand->LinkEndChild(xvalue);
|
||||
|
||||
if (needs_response) {
|
||||
_session->send_command(doc);
|
||||
} else {
|
||||
delete doc;
|
||||
}
|
||||
} else if (operation == "call") {
|
||||
P3D_object *result =
|
||||
P3D_OBJECT_CALL(object, property_name.c_str(), values, num_values);
|
||||
|
||||
if (result != NULL) {
|
||||
xcommand->LinkEndChild(_session->p3dobj_to_xml(result));
|
||||
P3D_OBJECT_DECREF(result);
|
||||
}
|
||||
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);
|
||||
|
||||
// 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_DECREF(result);
|
||||
}
|
||||
|
||||
if (needs_response) {
|
||||
_session->send_command(doc);
|
||||
} else {
|
||||
delete doc;
|
||||
}
|
||||
} else if (operation == "eval") {
|
||||
P3D_object *result;
|
||||
if (num_values == 1) {
|
||||
P3D_object *expression = values[0];
|
||||
int size = P3D_OBJECT_GET_STRING(expression, NULL, 0);
|
||||
char *buffer = new char[size + 1];
|
||||
P3D_OBJECT_GET_STRING(expression, buffer, size + 1);
|
||||
result = P3D_OBJECT_EVAL(object, buffer);
|
||||
logfile << " eval " << *object << ": " << buffer << ", result = " << result << "\n";
|
||||
delete[] buffer;
|
||||
} else {
|
||||
// Wrong number of values. Error.
|
||||
result = NULL;
|
||||
}
|
||||
break;
|
||||
|
||||
case P3D_SO_eval:
|
||||
{
|
||||
P3D_object *result;
|
||||
if (request->_request._script._num_values == 1) {
|
||||
P3D_object *expression = request->_request._script._values[0];
|
||||
int size = P3D_OBJECT_GET_STRING(expression, NULL, 0);
|
||||
char *buffer = new char[size + 1];
|
||||
P3D_OBJECT_GET_STRING(expression, buffer, size + 1);
|
||||
result = P3D_OBJECT_EVAL(object, buffer);
|
||||
logfile << " eval " << *object << ": " << buffer << ", result = " << result << "\n";
|
||||
delete[] buffer;
|
||||
} else {
|
||||
// Wrong number of values. Error.
|
||||
result = NULL;
|
||||
}
|
||||
|
||||
// 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_DECREF(result);
|
||||
}
|
||||
|
||||
logfile << "eval response: " << *doc << "\n";
|
||||
|
||||
if (needs_response) {
|
||||
_session->send_command(doc);
|
||||
} else {
|
||||
delete doc;
|
||||
}
|
||||
|
||||
if (result != NULL) {
|
||||
xcommand->LinkEndChild(_session->p3dobj_to_xml(result));
|
||||
P3D_OBJECT_DECREF(result);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (needs_response) {
|
||||
_session->send_command(doc);
|
||||
} else {
|
||||
delete doc;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
#include "p3dFileDownload.h"
|
||||
#include "p3dFileParams.h"
|
||||
#include "p3dWindowParams.h"
|
||||
#include "p3dReferenceCount.h"
|
||||
#include "get_tinyxml.h"
|
||||
|
||||
#include <deque>
|
||||
|
|
@ -35,7 +36,7 @@ class P3DObject;
|
|||
// Description : This is an instance of a Panda3D window, as seen in
|
||||
// the parent-level process.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class P3DInstance : public P3D_instance {
|
||||
class P3DInstance : public P3D_instance, public P3DReferenceCount {
|
||||
public:
|
||||
P3DInstance(P3D_request_ready_func *func, void *user_data);
|
||||
~P3DInstance();
|
||||
|
|
@ -51,7 +52,9 @@ public:
|
|||
|
||||
bool has_request();
|
||||
P3D_request *get_request();
|
||||
void add_request(P3D_request *request);
|
||||
void bake_requests();
|
||||
void add_raw_request(TiXmlDocument *doc);
|
||||
void add_baked_request(P3D_request *request);
|
||||
void finish_request(P3D_request *request, bool handled);
|
||||
|
||||
bool feed_url_stream(int unique_id,
|
||||
|
|
@ -88,8 +91,12 @@ private:
|
|||
};
|
||||
|
||||
void send_browser_script_object();
|
||||
void handle_notify_request(P3D_request *request);
|
||||
void handle_script_request(P3D_request *request);
|
||||
P3D_request *make_p3d_request(TiXmlElement *xrequest);
|
||||
void handle_notify_request(const string &message);
|
||||
void handle_script_request(const string &operation, P3D_object *object,
|
||||
const string &property_name,
|
||||
P3D_object *values[], int num_values,
|
||||
bool needs_response, int unique_id);
|
||||
void make_splash_window();
|
||||
void install_progress(P3DPackage *package, double progress);
|
||||
|
||||
|
|
@ -105,7 +112,10 @@ private:
|
|||
int _instance_id;
|
||||
string _session_key;
|
||||
string _python_version;
|
||||
|
||||
// Not ref-counted: session is the parent.
|
||||
P3DSession *_session;
|
||||
|
||||
P3DSplashWindow *_splash_window;
|
||||
bool _instance_window_opened;
|
||||
|
||||
|
|
@ -115,11 +125,18 @@ private:
|
|||
typedef map<int, P3DDownload *> Downloads;
|
||||
Downloads _downloads;
|
||||
|
||||
// The _raw_requests queue might be filled up by the read thread, so
|
||||
// we protect it in a lock.
|
||||
LOCK _request_lock;
|
||||
typedef deque<P3D_request *> Requests;
|
||||
Requests _pending_requests;
|
||||
typedef deque<TiXmlDocument *> RawRequests;
|
||||
RawRequests _raw_requests;
|
||||
bool _requested_stop;
|
||||
|
||||
// The _baked_requests queue is only touched in the main thread; no
|
||||
// lock needed.
|
||||
typedef deque<P3D_request *> BakedRequests;
|
||||
BakedRequests _baked_requests;
|
||||
|
||||
static int _next_instance_id;
|
||||
|
||||
friend class P3DSession;
|
||||
|
|
|
|||
|
|
@ -138,6 +138,7 @@ initialize() {
|
|||
P3DInstance *P3DInstanceManager::
|
||||
create_instance(P3D_request_ready_func *func, void *user_data) {
|
||||
P3DInstance *inst = new P3DInstance(func, user_data);
|
||||
inst->ref();
|
||||
_instances.insert(inst);
|
||||
|
||||
return inst;
|
||||
|
|
@ -164,6 +165,7 @@ start_instance(P3DInstance *inst, const string &p3d_filename,
|
|||
Sessions::iterator si = _sessions.find(inst->get_session_key());
|
||||
if (si == _sessions.end()) {
|
||||
session = new P3DSession(inst);
|
||||
session->ref();
|
||||
bool inserted = _sessions.insert(Sessions::value_type(session->get_session_key(), session)).second;
|
||||
assert(inserted);
|
||||
} else {
|
||||
|
|
@ -197,10 +199,11 @@ finish_instance(P3DInstance *inst) {
|
|||
// session.
|
||||
if (session->get_num_instances() == 0) {
|
||||
_sessions.erase(session->get_session_key());
|
||||
delete session;
|
||||
session->shutdown();
|
||||
unref_delete(session);
|
||||
}
|
||||
|
||||
delete inst;
|
||||
unref_delete(inst);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -24,6 +24,8 @@ P3DPythonObject(P3DSession *session, int object_id) :
|
|||
_session(session),
|
||||
_object_id(object_id)
|
||||
{
|
||||
_session->ref();
|
||||
nout << "new P3DPythonObject " << this << " : " << object_id << "\n" << flush;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -33,7 +35,12 @@ P3DPythonObject(P3DSession *session, int object_id) :
|
|||
////////////////////////////////////////////////////////////////////
|
||||
P3DPythonObject::
|
||||
~P3DPythonObject() {
|
||||
// TODO.
|
||||
nout << "del P3DPythonObject " << this << " : " << _object_id << "\n";
|
||||
// When the P3DPythonObject wrapper goes away, we have to inform the
|
||||
// child process that we no longer need the corresponding PyObject
|
||||
// to be kept around.
|
||||
_session->drop_pyobj(_object_id);
|
||||
unref_delete(_session);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -259,6 +259,18 @@ handle_command(TiXmlDocument *doc) {
|
|||
// Response from a script request.
|
||||
assert(!needs_response);
|
||||
nout << "Ignoring unexpected script_response\n";
|
||||
|
||||
} else if (strcmp(cmd, "drop_pyobj") == 0) {
|
||||
int object_id;
|
||||
if (xcommand->QueryIntAttribute("object_id", &object_id) == TIXML_SUCCESS) {
|
||||
nout << "got drop_pyobj(" << object_id << ")\n" << flush;
|
||||
SentObjects::iterator si = _sent_objects.find(object_id);
|
||||
if (si != _sent_objects.end()) {
|
||||
PyObject *obj = (*si).second;
|
||||
Py_DECREF(obj);
|
||||
_sent_objects.erase(si);
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
nout << "Unhandled command " << cmd << "\n";
|
||||
|
|
@ -666,6 +678,19 @@ py_request_func(PyObject *args) {
|
|||
nout << "sent: " << doc << "\n" << flush;
|
||||
_pipe_write << doc << flush;
|
||||
|
||||
} else if (strcmp(request_type, "drop_p3dobj") == 0) {
|
||||
// Release a particular P3D_object that we were holding a
|
||||
// reference to.
|
||||
int object_id;
|
||||
if (!PyArg_ParseTuple(extra_args, "i", &object_id)) {
|
||||
return NULL;
|
||||
}
|
||||
nout << "got drop_p3dobj(" << object_id << ")\n" << flush;
|
||||
|
||||
xrequest->SetAttribute("object_id", object_id);
|
||||
nout << "sent: " << doc << "\n" << flush;
|
||||
_pipe_write << doc << flush;
|
||||
|
||||
} else {
|
||||
string message = string("Unsupported request type: ") + string(request_type);
|
||||
PyErr_SetString(PyExc_ValueError, message.c_str());
|
||||
|
|
|
|||
|
|
@ -0,0 +1,72 @@
|
|||
// Filename: p3dReferenceCount.I
|
||||
// Created by: drose (09Jul09)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||
//
|
||||
// All use of this software is subject to the terms of the revised BSD
|
||||
// license. You should have received a copy of this license along
|
||||
// with this source code in a file named "LICENSE."
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DReferenceCount::Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
inline P3DReferenceCount::
|
||||
P3DReferenceCount() {
|
||||
_ref_count = 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DReferenceCount::Destructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
inline P3DReferenceCount::
|
||||
~P3DReferenceCount() {
|
||||
assert(_ref_count == 0);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DReferenceCount::ref
|
||||
// Access: Public
|
||||
// Description: Explicitly increments the reference count.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
inline void P3DReferenceCount::
|
||||
ref() const {
|
||||
++((P3DReferenceCount *)this)->_ref_count;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DReferenceCount::unref
|
||||
// Access: Published, Virtual
|
||||
// Description: Explicitly decrements the reference count. Usually,
|
||||
// you should call unref_delete() instead.
|
||||
//
|
||||
// The return value is true if the new reference count
|
||||
// is nonzero, false if it is zero.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
inline bool P3DReferenceCount::
|
||||
unref() const {
|
||||
return --(((P3DReferenceCount *)this)->_ref_count) != 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: unref_delete
|
||||
// Description: This global helper function will unref the given
|
||||
// P3DReferenceCount object, and if the reference count
|
||||
// reaches zero, automatically delete it.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
template<class RefCountType>
|
||||
inline void
|
||||
unref_delete(RefCountType *ptr) {
|
||||
if (!ptr->unref()) {
|
||||
delete ptr;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
// Filename: p3dReferenceCount.cxx
|
||||
// Created by: drose (09Jul09)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||
//
|
||||
// All use of this software is subject to the terms of the revised BSD
|
||||
// license. You should have received a copy of this license along
|
||||
// with this source code in a file named "LICENSE."
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "p3dReferenceCount.h"
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
// Filename: p3dReferenceCount.h
|
||||
// Created by: drose (09Jul09)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||
//
|
||||
// All use of this software is subject to the terms of the revised BSD
|
||||
// license. You should have received a copy of this license along
|
||||
// with this source code in a file named "LICENSE."
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef P3DREFERENCECOUNT_H
|
||||
#define P3DREFERENCECOUNT_H
|
||||
|
||||
#include "p3d_plugin_common.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : P3DReferenceCount
|
||||
// Description : A base class for reference-counted objects in this
|
||||
// module. We follow the Panda convention, rather than
|
||||
// the Pythong convention: the reference count of a new
|
||||
// object is initially 0.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class P3DReferenceCount {
|
||||
public:
|
||||
inline P3DReferenceCount();
|
||||
inline ~P3DReferenceCount();
|
||||
|
||||
inline void ref() const;
|
||||
inline bool unref() const;
|
||||
|
||||
private:
|
||||
int _ref_count;
|
||||
};
|
||||
|
||||
template<class RefCountType>
|
||||
inline void unref_delete(RefCountType *ptr);
|
||||
|
||||
#include "p3dReferenceCount.I"
|
||||
|
||||
#endif
|
||||
|
|
@ -69,14 +69,26 @@ P3DSession(P3DInstance *inst) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DSession::Destructor
|
||||
// Access: Public
|
||||
// Description: Terminates the session by shutting down Python and
|
||||
// stopping the subprocess.
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
P3DSession::
|
||||
~P3DSession() {
|
||||
assert(!_p3dpython_running);
|
||||
DESTROY_LOCK(_instances_lock);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DSession::shutdown
|
||||
// Access: Public
|
||||
// Description: Terminates the session by shutting down Python and
|
||||
// stopping the subprocess.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void P3DSession::
|
||||
shutdown() {
|
||||
if (_panda3d_callback != NULL) {
|
||||
_panda3d->cancel_callback(_panda3d_callback);
|
||||
delete _panda3d_callback;
|
||||
_panda3d_callback = NULL;
|
||||
}
|
||||
|
||||
if (_p3dpython_running) {
|
||||
|
|
@ -106,12 +118,13 @@ P3DSession::
|
|||
}
|
||||
|
||||
CloseHandle(_p3dpython_handle);
|
||||
|
||||
#else // _WIN32
|
||||
|
||||
// TODO: posix kill().
|
||||
|
||||
#endif // _WIN32
|
||||
|
||||
_p3dpython_running = false;
|
||||
}
|
||||
|
||||
// If there are any leftover commands in the queue (presumably
|
||||
|
|
@ -124,7 +137,6 @@ P3DSession::
|
|||
_commands.clear();
|
||||
|
||||
join_read_thread();
|
||||
DESTROY_LOCK(_instances_lock);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -143,6 +155,7 @@ start_instance(P3DInstance *inst) {
|
|||
assert(inst->get_session_key() == _session_key);
|
||||
assert(inst->get_python_version() == _python_version);
|
||||
|
||||
inst->ref();
|
||||
ACQUIRE_LOCK(_instances_lock);
|
||||
inst->_session = this;
|
||||
bool inserted = _instances.insert(Instances::value_type(inst->get_instance_id(), inst)).second;
|
||||
|
|
@ -200,6 +213,7 @@ terminate_instance(P3DInstance *inst) {
|
|||
_instances.erase(inst->get_instance_id());
|
||||
}
|
||||
RELEASE_LOCK(_instances_lock);
|
||||
unref_delete(inst);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -284,6 +298,16 @@ command_and_response(TiXmlDocument *command) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
// Make sure we bake requests while we are waiting, to process
|
||||
// recursive script requests. (The child process might have to
|
||||
// wait for us to process some of these before it can fulfill the
|
||||
// command we're actually waiting for.)
|
||||
Instances::iterator ii;
|
||||
for (ii = _instances.begin(); ii != _instances.end(); ++ii) {
|
||||
P3DInstance *inst = (*ii).second;
|
||||
inst->bake_requests();
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
// Make sure we process the Windows event loop while we're
|
||||
// waiting, or everything that depends on Windows messages--in
|
||||
|
|
@ -370,6 +394,7 @@ xml_to_p3dobj(const TiXmlElement *xvalue) {
|
|||
}
|
||||
|
||||
P3D_object *obj = (*si).second;
|
||||
|
||||
P3D_OBJECT_INCREF(obj);
|
||||
return obj;
|
||||
}
|
||||
|
|
@ -472,6 +497,69 @@ p3dobj_to_xml(P3D_object *obj) {
|
|||
return xvalue;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DSession::signal_request_ready
|
||||
// Access: Public
|
||||
// Description: May be called in any thread to indicate that a new
|
||||
// P3D_request is available in the indicated instance.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void P3DSession::
|
||||
signal_request_ready(P3DInstance *inst) {
|
||||
// Since a new request might require baking, we should wake up a
|
||||
// blocked command_and_request() process, so the main thread can go
|
||||
// back and bake the new request.
|
||||
|
||||
// Technically, a response isn't really ready now, but we still need
|
||||
// the main thread to wake up and look around for a bit.
|
||||
_response_ready.acquire();
|
||||
_response_ready.notify();
|
||||
_response_ready.release();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DSession::drop_pyobj
|
||||
// Access: Public
|
||||
// Description: If the session is still active, issues the command to
|
||||
// the child process to release the indicated PyObject
|
||||
// from its table. This is intended to be called
|
||||
// strictly by the P3DPythonObject destructor.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void P3DSession::
|
||||
drop_pyobj(int object_id) {
|
||||
nout << "got drop_pyobj(" << object_id << ")\n" << flush;
|
||||
if (_p3dpython_running) {
|
||||
TiXmlDocument doc;
|
||||
TiXmlDeclaration *decl = new TiXmlDeclaration("1.0", "utf-8", "");
|
||||
TiXmlElement *xcommand = new TiXmlElement("command");
|
||||
xcommand->SetAttribute("cmd", "drop_pyobj");
|
||||
xcommand->SetAttribute("object_id", object_id);
|
||||
doc.LinkEndChild(decl);
|
||||
doc.LinkEndChild(xcommand);
|
||||
nout << "sent: " << doc << "\n" << flush;
|
||||
_pipe_write << doc << flush;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DSession::drop_p3dobj
|
||||
// Access: Public
|
||||
// Description: Responds to a drop_p3dobj message from the child
|
||||
// process indicating that a particular P3D_object is no
|
||||
// longer being used by the child. This removes the
|
||||
// corresponding P3D_object from our tables and
|
||||
// decrements its reference count.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void P3DSession::
|
||||
drop_p3dobj(int object_id) {
|
||||
nout << "got drop_p3dobj(" << object_id << ")\n" << flush;
|
||||
SentObjects::iterator si = _sent_objects.find(object_id);
|
||||
if (si != _sent_objects.end()) {
|
||||
P3D_object *obj = (*si).second;
|
||||
P3D_OBJECT_DECREF(obj);
|
||||
_sent_objects.erase(si);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DSession::install_progress
|
||||
// Access: Private
|
||||
|
|
@ -676,103 +764,16 @@ rt_handle_request(TiXmlDocument *doc) {
|
|||
ii = _instances.find(instance_id);
|
||||
if (ii != _instances.end()) {
|
||||
P3DInstance *inst = (*ii).second;
|
||||
P3D_request *request = rt_make_p3d_request(xrequest);
|
||||
if (request != NULL) {
|
||||
inst->add_request(request);
|
||||
}
|
||||
inst->add_raw_request(doc);
|
||||
doc = NULL;
|
||||
}
|
||||
RELEASE_LOCK(_instances_lock);
|
||||
}
|
||||
}
|
||||
|
||||
delete doc;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DSession::rt_make_p3d_request
|
||||
// Access: Private
|
||||
// Description: Creates a new P3D_request structure from the XML.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
P3D_request *P3DSession::
|
||||
rt_make_p3d_request(TiXmlElement *xrequest) {
|
||||
P3D_request *request = NULL;
|
||||
|
||||
const char *rtype = xrequest->Attribute("rtype");
|
||||
if (rtype != NULL) {
|
||||
if (strcmp(rtype, "notify") == 0) {
|
||||
const char *message = xrequest->Attribute("message");
|
||||
if (message != NULL) {
|
||||
request = new P3D_request;
|
||||
request->_request_type = P3D_RT_notify;
|
||||
request->_request._notify._message = strdup(message);
|
||||
}
|
||||
|
||||
} else if (strcmp(rtype, "script") == 0) {
|
||||
const char *operation = xrequest->Attribute("operation");
|
||||
TiXmlElement *xobject = xrequest->FirstChildElement("object");
|
||||
const char *property_name = xrequest->Attribute("property_name");
|
||||
int needs_response = 0;
|
||||
xrequest->Attribute("needs_response", &needs_response);
|
||||
int unique_id = 0;
|
||||
xrequest->Attribute("unique_id", &unique_id);
|
||||
|
||||
if (operation != NULL && xobject != NULL) {
|
||||
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 if (strcmp(operation, "eval") == 0) {
|
||||
op = P3D_SO_eval;
|
||||
} 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._needs_response = (needs_response != 0);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
nout << "Ignoring request of type " << rtype << "\n";
|
||||
}
|
||||
if (doc != NULL) {
|
||||
delete doc;
|
||||
}
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
#include "handleStream.h"
|
||||
#include "p3dPackage.h"
|
||||
#include "p3dConditionVar.h"
|
||||
#include "p3dReferenceCount.h"
|
||||
#include "get_tinyxml.h"
|
||||
|
||||
#include <map>
|
||||
|
|
@ -34,11 +35,13 @@ class P3DProgressWindow;
|
|||
// might include one or more P3DInstance objects running
|
||||
// in the same memory space with each other.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class P3DSession {
|
||||
class P3DSession : public P3DReferenceCount {
|
||||
public:
|
||||
P3DSession(P3DInstance *inst);
|
||||
~P3DSession();
|
||||
|
||||
void shutdown();
|
||||
|
||||
inline const string &get_session_key() const;
|
||||
inline const string &get_python_version() const;
|
||||
|
||||
|
|
@ -52,6 +55,11 @@ public:
|
|||
P3D_object *xml_to_p3dobj(const TiXmlElement *xvalue);
|
||||
TiXmlElement *p3dobj_to_xml(P3D_object *obj);
|
||||
|
||||
void signal_request_ready(P3DInstance *inst);
|
||||
|
||||
void drop_pyobj(int object_id);
|
||||
void drop_p3dobj(int object_id);
|
||||
|
||||
private:
|
||||
void install_progress(P3DPackage *package, double progress);
|
||||
void start_p3dpython();
|
||||
|
|
@ -65,7 +73,6 @@ private:
|
|||
void rt_thread_run();
|
||||
void rt_terminate();
|
||||
void rt_handle_request(TiXmlDocument *doc);
|
||||
P3D_request *rt_make_p3d_request(TiXmlElement *xrequest);
|
||||
|
||||
#ifdef _WIN32
|
||||
static HANDLE
|
||||
|
|
|
|||
|
|
@ -580,7 +580,6 @@ typedef enum {
|
|||
P3D_RT_get_url,
|
||||
P3D_RT_post_url,
|
||||
P3D_RT_notify,
|
||||
P3D_RT_script,
|
||||
} P3D_request_type;
|
||||
|
||||
/* Structures corresponding to the request types in the above enum. */
|
||||
|
|
@ -624,27 +623,6 @@ typedef struct {
|
|||
const char *_message;
|
||||
} P3D_request_notify;
|
||||
|
||||
/* A script object request. This is used to call out into the
|
||||
browser_script_object (above). This request is handled internally
|
||||
by the core API, and may safely be ignored by the host.
|
||||
*/
|
||||
typedef enum {
|
||||
P3D_SO_get_property,
|
||||
P3D_SO_set_property,
|
||||
P3D_SO_del_property,
|
||||
P3D_SO_call,
|
||||
P3D_SO_eval,
|
||||
} P3D_script_operation;
|
||||
typedef struct {
|
||||
P3D_object *_object;
|
||||
P3D_script_operation _op;
|
||||
const char *_property_name;
|
||||
P3D_object **_values;
|
||||
int _num_values;
|
||||
bool _needs_response;
|
||||
int _unique_id;
|
||||
} P3D_request_script;
|
||||
|
||||
/* This is the overall structure that represents a single request. It
|
||||
is returned by P3D_instance_get_request(). */
|
||||
typedef struct {
|
||||
|
|
@ -655,7 +633,6 @@ typedef struct {
|
|||
P3D_request_get_url _get_url;
|
||||
P3D_request_post_url _post_url;
|
||||
P3D_request_notify _notify;
|
||||
P3D_request_script _script;
|
||||
} _request;
|
||||
} P3D_request;
|
||||
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
#include "p3dObject.cxx"
|
||||
#include "p3dPackage.cxx"
|
||||
#include "p3dPythonObject.cxx"
|
||||
#include "p3dReferenceCount.cxx"
|
||||
#include "p3dSession.cxx"
|
||||
#include "p3dSplashWindow.cxx"
|
||||
#include "p3dStringObject.cxx"
|
||||
|
|
|
|||
|
|
@ -377,13 +377,20 @@ class AppRunner(DirectObject):
|
|||
uniqueId = self.nextScriptId
|
||||
self.nextScriptId += 1
|
||||
self.sendRequest('script', operation, object,
|
||||
propertyName, value, needsResponse, uniqueId);
|
||||
propertyName, value, needsResponse, uniqueId)
|
||||
|
||||
if needsResponse:
|
||||
# Now wait for the response to come in.
|
||||
result = self.sendRequest('wait_script_response', uniqueId)
|
||||
return result
|
||||
|
||||
def dropObject(self, objectId):
|
||||
""" Inform the parent process that we no longer have an
|
||||
interest in the P3D_object corresponding to the indicated
|
||||
objectId. """
|
||||
|
||||
self.sendRequest('drop_p3dobj', objectId)
|
||||
|
||||
def parseSysArgs(self):
|
||||
""" Converts sys.argv into (p3dFilename, tokens). """
|
||||
import getopt
|
||||
|
|
@ -444,6 +451,12 @@ class BrowserObject:
|
|||
# the object to its parent.
|
||||
self.__dict__['_BrowserObject__boundMethod'] = (None, None)
|
||||
|
||||
def __del__(self):
|
||||
# When the BrowserObject destructs, tell the parent process it
|
||||
# doesn't need to keep around its corresponding P3D_object any
|
||||
# more.
|
||||
self.__runner.dropObject(self.__objectId)
|
||||
|
||||
def __str__(self):
|
||||
parentObj, attribName = self.__boundMethod
|
||||
if parentObj:
|
||||
|
|
@ -546,7 +559,7 @@ class BrowserObject:
|
|||
else:
|
||||
raise IndexError(key)
|
||||
|
||||
return value;
|
||||
return value
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
result = self.__runner.scriptRequest('set_property', self,
|
||||
|
|
|
|||
Loading…
Reference in New Issue