concrete objects
This commit is contained in:
parent
3a902bdaf3
commit
1b6bb92da5
|
|
@ -30,6 +30,8 @@
|
|||
p3d_plugin_config.h \
|
||||
p3d_plugin_common.h \
|
||||
p3dBoolObject.h \
|
||||
p3dConcreteSequence.h \
|
||||
p3dConcreteStruct.h \
|
||||
p3dConditionVar.h p3dConditionVar.I \
|
||||
p3dDownload.h p3dDownload.I \
|
||||
p3dFileDownload.h p3dFileDownload.I \
|
||||
|
|
@ -56,6 +58,8 @@
|
|||
#define INCLUDED_SOURCES \
|
||||
p3d_plugin.cxx \
|
||||
p3dBoolObject.cxx \
|
||||
p3dConcreteSequence.cxx \
|
||||
p3dConcreteStruct.cxx \
|
||||
p3dConditionVar.cxx \
|
||||
p3dDownload.cxx \
|
||||
p3dFileDownload.cxx \
|
||||
|
|
|
|||
|
|
@ -0,0 +1,253 @@
|
|||
// Filename: p3dConcreteSequence.cxx
|
||||
// Created by: drose (30Jun09)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 "p3dConcreteSequence.h"
|
||||
#include "p3dSession.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DConcreteSequence::Default Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
P3DConcreteSequence::
|
||||
P3DConcreteSequence() {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DConcreteSequence::Destructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
P3DConcreteSequence::
|
||||
~P3DConcreteSequence() {
|
||||
Elements::iterator ei;
|
||||
for (ei = _elements.begin(); ei != _elements.end(); ++ei) {
|
||||
P3D_OBJECT_DECREF(*ei);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DConcreteSequence::is_sequence_object
|
||||
// Access: Public, Virtual
|
||||
// Description: Returns true if this is actually an instance of a
|
||||
// P3DConcreteSequence, false otherwise.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool P3DConcreteSequence::
|
||||
is_sequence_object() {
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DConcreteSequence::get_type
|
||||
// Access: Public, Virtual
|
||||
// Description: Returns the fundamental type of this kind of object.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
P3D_object_type P3DConcreteSequence::
|
||||
get_type() {
|
||||
return P3D_OT_object;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DConcreteSequence::get_bool
|
||||
// Access: Public, Virtual
|
||||
// Description: Returns the object value coerced to a boolean, if
|
||||
// possible.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool P3DConcreteSequence::
|
||||
get_bool() {
|
||||
return !_elements.empty();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DConcreteSequence::make_string
|
||||
// Access: Public, Virtual
|
||||
// Description: Fills the indicated C++ string object with the value
|
||||
// of this object coerced to a string.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void P3DConcreteSequence::
|
||||
make_string(string &value) {
|
||||
ostringstream strm;
|
||||
strm << "[";
|
||||
if (!_elements.empty()) {
|
||||
strm << *_elements[0];
|
||||
for (size_t i = 1; i < _elements.size(); ++i) {
|
||||
strm << ", " << *_elements[i];
|
||||
}
|
||||
}
|
||||
strm << "]";
|
||||
|
||||
value = strm.str();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DConcreteSequence::get_property
|
||||
// Access: Public, Virtual
|
||||
// Description: Returns the named property element in the object. The
|
||||
// return value is a new-reference P3D_object, or NULL
|
||||
// on error.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
P3D_object *P3DConcreteSequence::
|
||||
get_property(const string &property) {
|
||||
// We only understand integer "property" names.
|
||||
char *endptr;
|
||||
int index = strtoul(property.c_str(), &endptr, 10);
|
||||
if (*endptr != '\0') {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return get_element(index);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DConcreteSequence::set_property
|
||||
// Access: Public, Virtual
|
||||
// Description: Modifies (or deletes, if value is NULL) the named
|
||||
// property element in the object. Returns true on
|
||||
// success, false on failure.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool P3DConcreteSequence::
|
||||
set_property(const string &property, P3D_object *value) {
|
||||
// We only understand integer "property" names.
|
||||
char *endptr;
|
||||
int index = strtoul(property.c_str(), &endptr, 10);
|
||||
if (*endptr != '\0') {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return set_element(index, value);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DConcreteSequence::fill_xml
|
||||
// Access: Public, Virtual
|
||||
// Description: If this object has a valid XML representation for the
|
||||
// indicated session (that hasn't already been
|
||||
// implemented by the generic code in P3DSession), this
|
||||
// method will apply it to the indicated "value" element
|
||||
// and return true. Otherwise, this method will leave
|
||||
// the element unchanged and return false.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool P3DConcreteSequence::
|
||||
fill_xml(TiXmlElement *xvalue, P3DSession *session) {
|
||||
xvalue->SetAttribute("type", "concrete_sequence");
|
||||
Elements::const_iterator ei;
|
||||
for (ei = _elements.begin(); ei != _elements.end(); ++ei) {
|
||||
xvalue->LinkEndChild(session->p3dobj_to_xml(*ei));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DConcreteSequence::get_object_array
|
||||
// Access: Public
|
||||
// Description: Returns a pointer to the array of objects represented
|
||||
// by this object. Most objects represent only
|
||||
// themselves, but a P3DConcreteSequence represents its
|
||||
// list.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
P3D_object **P3DConcreteSequence::
|
||||
get_object_array() {
|
||||
if (_elements.empty()) {
|
||||
return NULL;
|
||||
}
|
||||
return &_elements[0];
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DConcreteSequence::get_object_array_size
|
||||
// Access: Public
|
||||
// Description: Returns the number of elements in the array returned
|
||||
// by get_object_array().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
int P3DConcreteSequence::
|
||||
get_object_array_size() {
|
||||
return _elements.size();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DConcreteSequence::get_length
|
||||
// Access: Public
|
||||
// Description: Returns the number of items in the sequence.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
int P3DConcreteSequence::
|
||||
get_length() const {
|
||||
return _elements.size();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DConcreteSequence::get_element
|
||||
// Access: Public
|
||||
// Description: Returns the nth item in the sequence. The
|
||||
// return value is a new-reference P3DObject object, or
|
||||
// NULL on error.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
P3D_object *P3DConcreteSequence::
|
||||
get_element(int n) const {
|
||||
if (n >= 0 && n < (int)_elements.size()) {
|
||||
P3D_OBJECT_INCREF(_elements[n]);
|
||||
return _elements[n];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DConcreteSequence::set_element
|
||||
// Access: Public
|
||||
// Description: Modifies (or deletes, if value is NULL) the nth item
|
||||
// in the sequence. Returns true on success, false on
|
||||
// failure.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool P3DConcreteSequence::
|
||||
set_element(int n, P3D_object *value) {
|
||||
if (value == NULL) {
|
||||
// Delete an element.
|
||||
if (n < 0 || n >= (int)_elements.size()) {
|
||||
// Invalid index.
|
||||
return false;
|
||||
}
|
||||
P3D_OBJECT_DECREF(_elements[n]);
|
||||
_elements.erase(_elements.begin() + n);
|
||||
return true;
|
||||
|
||||
} else if (n == _elements.size()) {
|
||||
// Append an element.
|
||||
append(value);
|
||||
return true;
|
||||
|
||||
} else {
|
||||
// Replace an element.
|
||||
if (n < 0 || n >= (int)_elements.size()) {
|
||||
// Invalid index.
|
||||
return false;
|
||||
}
|
||||
|
||||
P3D_OBJECT_INCREF(value);
|
||||
P3D_OBJECT_DECREF(_elements[n]);
|
||||
_elements[n] = value;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DConcreteSequence::append
|
||||
// Access: Public, Virtual
|
||||
// Description: Adds a new element to the end of the list.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void P3DConcreteSequence::
|
||||
append(P3D_object *value) {
|
||||
_elements.push_back(value);
|
||||
P3D_OBJECT_INCREF(value);
|
||||
}
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
// Filename: p3dConcreteSequence.h
|
||||
// Created by: drose (30Jun09)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 P3DCONCRETESEQUENCE_H
|
||||
#define P3DCONCRETESEQUENCE_H
|
||||
|
||||
#include "p3d_plugin_common.h"
|
||||
#include "p3dObject.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : P3DConcreteSequence
|
||||
// Description : An object type that contains a sequence of objects,
|
||||
// which is passed by value between Python and
|
||||
// JavaScript, so may be more optimal for small lists
|
||||
// that are accessed repeatedly.
|
||||
//
|
||||
// This is converted from a Python "tuple" object.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class P3DConcreteSequence : public P3DObject {
|
||||
public:
|
||||
P3DConcreteSequence();
|
||||
virtual ~P3DConcreteSequence();
|
||||
|
||||
virtual bool is_sequence_object();
|
||||
|
||||
virtual P3D_object_type get_type();
|
||||
virtual bool get_bool();
|
||||
|
||||
virtual void make_string(string &value);
|
||||
|
||||
virtual P3D_object *get_property(const string &property);
|
||||
virtual bool set_property(const string &property, P3D_object *value);
|
||||
|
||||
virtual bool fill_xml(TiXmlElement *xvalue, P3DSession *session);
|
||||
virtual P3D_object **get_object_array();
|
||||
virtual int get_object_array_size();
|
||||
|
||||
int get_length() const;
|
||||
P3D_object *get_element(int n) const;
|
||||
bool set_element(int n, P3D_object *value);
|
||||
void append(P3D_object *value);
|
||||
|
||||
private:
|
||||
typedef vector<P3D_object *> Elements;
|
||||
Elements _elements;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -0,0 +1,158 @@
|
|||
// Filename: p3dConcreteStruct.cxx
|
||||
// Created by: drose (14Jul09)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 "p3dConcreteStruct.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DConcreteStruct::Default Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
P3DConcreteStruct::
|
||||
P3DConcreteStruct() {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DConcreteStruct::Destructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
P3DConcreteStruct::
|
||||
~P3DConcreteStruct() {
|
||||
Elements::iterator ei;
|
||||
for (ei = _elements.begin(); ei != _elements.end(); ++ei) {
|
||||
P3D_OBJECT_DECREF((*ei).second);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DConcreteStruct::get_type
|
||||
// Access: Public, Virtual
|
||||
// Description: Returns the fundamental type of this kind of object.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
P3D_object_type P3DConcreteStruct::
|
||||
get_type() {
|
||||
return P3D_OT_object;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DConcreteStruct::get_bool
|
||||
// Access: Public, Virtual
|
||||
// Description: Returns the object value coerced to a boolean, if
|
||||
// possible.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool P3DConcreteStruct::
|
||||
get_bool() {
|
||||
return !_elements.empty();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DConcreteStruct::make_string
|
||||
// Access: Public, Virtual
|
||||
// Description: Fills the indicated C++ string object with the value
|
||||
// of this object coerced to a string.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void P3DConcreteStruct::
|
||||
make_string(string &value) {
|
||||
ostringstream strm;
|
||||
strm << "{";
|
||||
if (!_elements.empty()) {
|
||||
Elements::iterator ei;
|
||||
ei = _elements.begin();
|
||||
strm << (*ei).first << ": " << *(*ei).second;
|
||||
++ei;
|
||||
while (ei != _elements.end()) {
|
||||
strm << ", " << (*ei).first << ": " << *(*ei).second;
|
||||
++ei;
|
||||
}
|
||||
}
|
||||
strm << "}";
|
||||
|
||||
value = strm.str();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DConcreteStruct::get_property
|
||||
// Access: Public, Virtual
|
||||
// Description: Returns the named property element in the object. The
|
||||
// return value is a new-reference P3D_object, or NULL
|
||||
// on error.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
P3D_object *P3DConcreteStruct::
|
||||
get_property(const string &property) {
|
||||
Elements::const_iterator ei = _elements.find(property);
|
||||
if (ei != _elements.end()) {
|
||||
P3D_OBJECT_INCREF((*ei).second);
|
||||
return (*ei).second;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DConcreteStruct::set_property
|
||||
// Access: Public, Virtual
|
||||
// Description: Modifies (or deletes, if value is NULL) the named
|
||||
// property element in the object. Returns true on
|
||||
// success, false on failure.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool P3DConcreteStruct::
|
||||
set_property(const string &property, P3D_object *value) {
|
||||
if (value == NULL) {
|
||||
// Delete an element.
|
||||
Elements::iterator ei = _elements.find(property);
|
||||
if (ei == _elements.end()) {
|
||||
// Invalid property.
|
||||
return false;
|
||||
}
|
||||
P3D_OBJECT_DECREF((*ei).second);
|
||||
_elements.erase(ei);
|
||||
return true;
|
||||
|
||||
} else {
|
||||
// Replace or insert an element.
|
||||
P3D_OBJECT_INCREF(value);
|
||||
pair<Elements::iterator, bool> result = _elements.insert(Elements::value_type(property, value));
|
||||
if (!result.second) {
|
||||
// Replacing an element.
|
||||
Elements::iterator ei = result.first;
|
||||
P3D_OBJECT_DECREF((*ei).second);
|
||||
(*ei).second = value;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DConcreteStruct::fill_xml
|
||||
// Access: Public, Virtual
|
||||
// Description: If this object has a valid XML representation for the
|
||||
// indicated session (that hasn't already been
|
||||
// implemented by the generic code in P3DSession), this
|
||||
// method will apply it to the indicated "value" element
|
||||
// and return true. Otherwise, this method will leave
|
||||
// the element unchanged and return false.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool P3DConcreteStruct::
|
||||
fill_xml(TiXmlElement *xvalue, P3DSession *session) {
|
||||
xvalue->SetAttribute("type", "concrete_struct");
|
||||
Elements::const_iterator ei;
|
||||
for (ei = _elements.begin(); ei != _elements.end(); ++ei) {
|
||||
TiXmlElement *xitem = session->p3dobj_to_xml((*ei).second);
|
||||
xitem->SetAttribute("key", (*ei).first);
|
||||
xvalue->LinkEndChild(xitem);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
// Filename: p3dConcreteStruct.h
|
||||
// Created by: drose (14Jul09)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 P3DCONCRETESTRUCT_H
|
||||
#define P3DCONCRETESTRUCT_H
|
||||
|
||||
#include "p3d_plugin_common.h"
|
||||
#include "p3dObject.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : P3DConcreteStruct
|
||||
// Description : A simple object that contains a standard mapping of
|
||||
// string -> element. It is passed by value between
|
||||
// Python and Javascript, so it may be more optimal for
|
||||
// relatively small objects.
|
||||
//
|
||||
// Methods are not supported.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class P3DConcreteStruct : public P3DObject {
|
||||
public:
|
||||
P3DConcreteStruct();
|
||||
virtual ~P3DConcreteStruct();
|
||||
|
||||
virtual P3D_object_type get_type();
|
||||
virtual bool get_bool();
|
||||
|
||||
virtual void make_string(string &value);
|
||||
|
||||
virtual P3D_object *get_property(const string &property);
|
||||
virtual bool set_property(const string &property, P3D_object *value);
|
||||
|
||||
virtual bool fill_xml(TiXmlElement *xvalue, P3DSession *session);
|
||||
|
||||
private:
|
||||
typedef map<string, P3D_object *> Elements;
|
||||
Elements _elements;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -140,7 +140,10 @@ wait(double timeout) {
|
|||
ts.tv_nsec += (int)((timeout - seconds) * 1000000.0);
|
||||
|
||||
int result = pthread_cond_timedwait(&_cvar, &_lock, &ts);
|
||||
assert(result == 0 || result == ETIMEDOUT);
|
||||
if (result != 0 && result != ETIMEDOUT && errno != ETIMEDOUT) {
|
||||
perror("pthread_cond_timedwait");
|
||||
assert(false);
|
||||
}
|
||||
|
||||
#endif // _WIN32
|
||||
}
|
||||
|
|
|
|||
|
|
@ -726,6 +726,7 @@ send_browser_script_object() {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
P3D_request *P3DInstance::
|
||||
make_p3d_request(TiXmlElement *xrequest) {
|
||||
P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
|
||||
P3D_request *request = NULL;
|
||||
|
||||
const char *rtype = xrequest->Attribute("rtype");
|
||||
|
|
@ -750,17 +751,13 @@ make_p3d_request(TiXmlElement *xrequest) {
|
|||
int unique_id = 0;
|
||||
xrequest->Attribute("unique_id", &unique_id);
|
||||
|
||||
vector<P3D_object *> values;
|
||||
P3D_object *value = NULL;
|
||||
TiXmlElement *xvalue = xrequest->FirstChildElement("value");
|
||||
while (xvalue != NULL) {
|
||||
P3D_object *value = _session->xml_to_p3dobj(xvalue);
|
||||
values.push_back(value);
|
||||
xvalue = xvalue->NextSiblingElement("value");
|
||||
if (xvalue != NULL) {
|
||||
value = _session->xml_to_p3dobj(xvalue);
|
||||
}
|
||||
|
||||
P3D_object **values_ptr = NULL;
|
||||
if (!values.empty()) {
|
||||
values_ptr = &values[0];
|
||||
if (value == NULL) {
|
||||
value = inst_mgr->new_none_object();
|
||||
}
|
||||
|
||||
if (operation != NULL && xobject != NULL) {
|
||||
|
|
@ -770,14 +767,11 @@ make_p3d_request(TiXmlElement *xrequest) {
|
|||
property_name = "";
|
||||
}
|
||||
|
||||
handle_script_request(operation, object, property_name,
|
||||
values_ptr, values.size(),
|
||||
handle_script_request(operation, object, property_name, value,
|
||||
(needs_response != 0), unique_id);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < values.size(); ++i) {
|
||||
P3D_OBJECT_DECREF(values[i]);
|
||||
}
|
||||
P3D_OBJECT_DECREF(value);
|
||||
|
||||
} else if (strcmp(rtype, "drop_p3dobj") == 0) {
|
||||
int object_id;
|
||||
|
|
@ -858,8 +852,7 @@ handle_notify_request(const string &message) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void P3DInstance::
|
||||
handle_script_request(const string &operation, P3D_object *object,
|
||||
const string &property_name,
|
||||
P3D_object *values[], int num_values,
|
||||
const string &property_name, P3D_object *value,
|
||||
bool needs_response, int unique_id) {
|
||||
|
||||
TiXmlDocument *doc = new TiXmlDocument;
|
||||
|
|
@ -883,13 +876,8 @@ handle_script_request(const string &operation, P3D_object *object,
|
|||
}
|
||||
|
||||
} 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;
|
||||
}
|
||||
bool result =
|
||||
P3D_OBJECT_SET_PROPERTY(object, property_name.c_str(), value);
|
||||
|
||||
TiXmlElement *xvalue = new TiXmlElement("value");
|
||||
xvalue->SetAttribute("type", "bool");
|
||||
|
|
@ -905,6 +893,17 @@ handle_script_request(const string &operation, P3D_object *object,
|
|||
xcommand->LinkEndChild(xvalue);
|
||||
|
||||
} else if (operation == "call") {
|
||||
// Convert the single value parameter into an array of parameters.
|
||||
P3D_object **values = &value;
|
||||
int num_values = 1;
|
||||
if (value->_class == &P3DObject::_object_class) {
|
||||
P3DObject *p3dobj = (P3DObject *)value;
|
||||
if (p3dobj->get_object_array_size() != -1) {
|
||||
values = p3dobj->get_object_array();
|
||||
num_values = p3dobj->get_object_array_size();
|
||||
}
|
||||
}
|
||||
|
||||
P3D_object *result =
|
||||
P3D_OBJECT_CALL(object, property_name.c_str(), values, num_values);
|
||||
|
||||
|
|
@ -915,18 +914,12 @@ handle_script_request(const string &operation, P3D_object *object,
|
|||
|
||||
} 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;
|
||||
}
|
||||
int size = P3D_OBJECT_GET_STRING(value, NULL, 0);
|
||||
char *buffer = new char[size + 1];
|
||||
P3D_OBJECT_GET_STRING(value, buffer, size + 1);
|
||||
result = P3D_OBJECT_EVAL(object, buffer);
|
||||
logfile << " eval " << *object << ": " << buffer << ", result = " << result << "\n";
|
||||
delete[] buffer;
|
||||
|
||||
if (result != NULL) {
|
||||
xcommand->LinkEndChild(_session->p3dobj_to_xml(result));
|
||||
|
|
|
|||
|
|
@ -102,8 +102,7 @@ private:
|
|||
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,
|
||||
const string &property_name, P3D_object *value,
|
||||
bool needs_response, int unique_id);
|
||||
void make_splash_window();
|
||||
void install_progress(P3DPackage *package, double progress);
|
||||
|
|
|
|||
|
|
@ -87,10 +87,12 @@ P3DInstanceManager::
|
|||
<< " " << _false_object->_ref_count
|
||||
<< "\n" << flush;
|
||||
|
||||
/*
|
||||
assert(_undefined_object->_ref_count == 1);
|
||||
assert(_none_object->_ref_count == 1);
|
||||
assert(_true_object->_ref_count == 1);
|
||||
assert(_false_object->_ref_count == 1);
|
||||
*/
|
||||
|
||||
P3D_OBJECT_DECREF(_undefined_object);
|
||||
P3D_OBJECT_DECREF(_none_object);
|
||||
|
|
|
|||
|
|
@ -199,17 +199,6 @@ P3DObject::
|
|||
assert(_ref_count == 0);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DObject::is_python_object
|
||||
// Access: Public, Virtual
|
||||
// Description: Returns true if this is actually an instance of a
|
||||
// P3DPythonObject, false otherwise.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool P3DObject::
|
||||
is_python_object() {
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DObject::get_int
|
||||
// Access: Public, Virtual
|
||||
|
|
@ -338,6 +327,47 @@ output(ostream &out) {
|
|||
out << value;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DObject::fill_xml
|
||||
// Access: Public, Virtual
|
||||
// Description: If this object has a valid XML representation for the
|
||||
// indicated session (that hasn't already been
|
||||
// implemented by the generic code in P3DSession), this
|
||||
// method will apply it to the indicated "value" element
|
||||
// and return true. Otherwise, this method will leave
|
||||
// the element unchanged and return false.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool P3DObject::
|
||||
fill_xml(TiXmlElement *xvalue, P3DSession *session) {
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DObject::get_object_array
|
||||
// Access: Public
|
||||
// Description: Returns a pointer to the array of objects represented
|
||||
// by this object, if any, or NULL if the object does
|
||||
// not represent an array of objects. This may also
|
||||
// return NULL for a zero-length array; use
|
||||
// get_object_array_size() to differentiate.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
P3D_object **P3DObject::
|
||||
get_object_array() {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DObject::get_object_array_size
|
||||
// Access: Public
|
||||
// Description: Returns the number of elements in the array returned
|
||||
// by get_object_array(), or -1 if this object does not
|
||||
// representan array of objects.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
int P3DObject::
|
||||
get_object_array_size() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DObject::get_bool_property
|
||||
// Access: Public
|
||||
|
|
|
|||
|
|
@ -33,8 +33,6 @@ protected:
|
|||
public:
|
||||
virtual ~P3DObject();
|
||||
|
||||
virtual bool is_python_object();
|
||||
|
||||
virtual P3D_object_type get_type()=0;
|
||||
virtual bool get_bool()=0;
|
||||
virtual int get_int();
|
||||
|
|
@ -53,6 +51,9 @@ public:
|
|||
virtual P3D_object *eval(const string &expression);
|
||||
|
||||
virtual void output(ostream &out);
|
||||
virtual bool fill_xml(TiXmlElement *xvalue, P3DSession *session);
|
||||
virtual P3D_object **get_object_array();
|
||||
virtual int get_object_array_size();
|
||||
|
||||
// Convenience functions.
|
||||
bool get_bool_property(const string &property);
|
||||
|
|
|
|||
|
|
@ -43,17 +43,6 @@ P3DPythonObject::
|
|||
unref_delete(_session);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DPythonObject::is_python_object
|
||||
// Access: Public, Virtual
|
||||
// Description: Returns true if this is actually an instance of a
|
||||
// P3DPythonObject, false otherwise.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool P3DPythonObject::
|
||||
is_python_object() {
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DPythonObject::get_type
|
||||
// Access: Public, Virtual
|
||||
|
|
@ -153,7 +142,7 @@ get_property(const string &property) {
|
|||
P3D_object *params[1];
|
||||
params[0] = new P3DStringObject(property);
|
||||
|
||||
P3D_object *result = call("__getattr__", params, 1);
|
||||
P3D_object *result = call("__get_property__", params, 1);
|
||||
P3D_OBJECT_DECREF(params[0]);
|
||||
return result;
|
||||
}
|
||||
|
|
@ -176,12 +165,12 @@ set_property(const string &property, P3D_object *value) {
|
|||
|
||||
if (value == NULL) {
|
||||
// Delete an attribute.
|
||||
result = call("__delattr__", params, 1);
|
||||
result = call("__del_property__", params, 1);
|
||||
|
||||
} else {
|
||||
// Set a new attribute.
|
||||
params[1] = value;
|
||||
result = call("__setattr__", params, 2);
|
||||
result = call("__set_property__", params, 2);
|
||||
}
|
||||
|
||||
P3D_OBJECT_DECREF(params[0]);
|
||||
|
|
@ -282,6 +271,31 @@ output(ostream &out) {
|
|||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DPythonObject::fill_xml
|
||||
// Access: Public, Virtual
|
||||
// Description: If this object has a valid XML representation for the
|
||||
// indicated session (that hasn't already been
|
||||
// implemented by the generic code in P3DSession), this
|
||||
// method will apply it to the indicated "value" element
|
||||
// and return true. Otherwise, this method will leave
|
||||
// the element unchanged and return false.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool P3DPythonObject::
|
||||
fill_xml(TiXmlElement *xvalue, P3DSession *session) {
|
||||
if (session == _session) {
|
||||
// If it's a P3DPythonObject from the same session, just send
|
||||
// the object_id down, since the actual implementation of this
|
||||
// object exists (as a Python object) in the sub-process space.
|
||||
xvalue->SetAttribute("type", "python");
|
||||
xvalue->SetAttribute("object_id", _object_id);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Otherwise, we have to send it as a browser object.
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DPythonObject::get_session
|
||||
// Access: Public
|
||||
|
|
|
|||
|
|
@ -33,8 +33,6 @@ public:
|
|||
P3DPythonObject(P3DSession *session, int object_id);
|
||||
virtual ~P3DPythonObject();
|
||||
|
||||
virtual bool is_python_object();
|
||||
|
||||
public:
|
||||
virtual P3D_object_type get_type();
|
||||
virtual bool get_bool();
|
||||
|
|
@ -51,6 +49,7 @@ public:
|
|||
P3D_object *params[], int num_params);
|
||||
|
||||
virtual void output(ostream &out);
|
||||
virtual bool fill_xml(TiXmlElement *xvalue, P3DSession *session);
|
||||
|
||||
P3DSession *get_session();
|
||||
int get_object_id();
|
||||
|
|
|
|||
|
|
@ -144,6 +144,13 @@ run_python() {
|
|||
return false;
|
||||
}
|
||||
|
||||
// Get the ConcreteStruct class.
|
||||
_concrete_struct_class = PyObject_GetAttrString(runp3d, "ConcreteStruct");
|
||||
if (_concrete_struct_class == NULL) {
|
||||
PyErr_Print();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the BrowserObject class.
|
||||
_browser_object_class = PyObject_GetAttrString(runp3d, "BrowserObject");
|
||||
if (_browser_object_class == NULL) {
|
||||
|
|
@ -324,7 +331,7 @@ handle_pyobj_command(TiXmlElement *xcommand, bool needs_response,
|
|||
doc.LinkEndChild(xresponse);
|
||||
|
||||
const char *op = xcommand->Attribute("op");
|
||||
if (op != NULL) {
|
||||
if (op != NULL && !PyErr_Occurred()) {
|
||||
if (strcmp(op, "get_panda_script_object") == 0) {
|
||||
// Get Panda's toplevel Python object.
|
||||
PyObject *obj = PyObject_CallMethod(_runner, (char*)"getPandaScriptObject", (char *)"");
|
||||
|
|
@ -396,20 +403,44 @@ handle_pyobj_command(TiXmlElement *xcommand, bool needs_response,
|
|||
strcmp(method_name, "toString") == 0) {
|
||||
result = PyObject_Str(obj);
|
||||
|
||||
} else if (strcmp(method_name, "__setattr__") == 0) {
|
||||
} else if (strcmp(method_name, "__set_property__") == 0) {
|
||||
// We call these methods __set_property__ et al instead of
|
||||
// __setattr__ et al, because they do not precisely
|
||||
// duplicate the Python semantics.
|
||||
char *property_name;
|
||||
PyObject *value;
|
||||
if (PyArg_ParseTuple(params, "sO", &property_name, &value)) {
|
||||
PyObject_SetAttrString(obj, property_name, value);
|
||||
result = Py_True;
|
||||
Py_INCREF(result);
|
||||
}
|
||||
bool success = false;
|
||||
|
||||
} else if (strcmp(method_name, "__delattr__") == 0) {
|
||||
char *property_name;
|
||||
if (PyArg_ParseTuple(params, "s", &property_name)) {
|
||||
// If it already exists as an attribute, update it there.
|
||||
if (PyObject_HasAttrString(obj, property_name)) {
|
||||
PyObject_DelAttrString(obj, property_name);
|
||||
if (PyObject_SetAttrString(obj, property_name, value) != -1) {
|
||||
success = true;
|
||||
} else {
|
||||
PyErr_Clear();
|
||||
}
|
||||
}
|
||||
|
||||
// If the object supports the mapping protocol, store it
|
||||
// in the object's dictionary.
|
||||
if (!success && PyMapping_Check(obj)) {
|
||||
if (PyMapping_SetItemString(obj, property_name, value) != -1) {
|
||||
success = true;
|
||||
} else {
|
||||
PyErr_Clear();
|
||||
}
|
||||
}
|
||||
|
||||
// Finally, try to store it on the object.
|
||||
if (!success) {
|
||||
if (PyObject_SetAttrString(obj, property_name, value) != -1) {
|
||||
success = true;
|
||||
} else {
|
||||
PyErr_Clear();
|
||||
}
|
||||
}
|
||||
|
||||
if (success) {
|
||||
result = Py_True;
|
||||
} else {
|
||||
result = Py_False;
|
||||
|
|
@ -417,13 +448,61 @@ handle_pyobj_command(TiXmlElement *xcommand, bool needs_response,
|
|||
Py_INCREF(result);
|
||||
}
|
||||
|
||||
} else if (strcmp(method_name, "__getattr__") == 0) {
|
||||
} else if (strcmp(method_name, "__del_property__") == 0) {
|
||||
char *property_name;
|
||||
if (PyArg_ParseTuple(params, "s", &property_name)) {
|
||||
bool success = false;
|
||||
|
||||
if (PyObject_HasAttrString(obj, property_name)) {
|
||||
if (PyObject_DelAttrString(obj, property_name) != -1) {
|
||||
success = true;
|
||||
} else {
|
||||
PyErr_Clear();
|
||||
}
|
||||
}
|
||||
|
||||
if (!success) {
|
||||
if (PyObject_DelItemString(obj, property_name) != -1) {
|
||||
success = true;
|
||||
} else {
|
||||
PyErr_Clear();
|
||||
}
|
||||
}
|
||||
|
||||
if (success) {
|
||||
result = Py_True;
|
||||
} else {
|
||||
result = Py_False;
|
||||
}
|
||||
Py_INCREF(result);
|
||||
}
|
||||
|
||||
} else if (strcmp(method_name, "__get_property__") == 0) {
|
||||
char *property_name;
|
||||
if (PyArg_ParseTuple(params, "s", &property_name)) {
|
||||
bool success = false;
|
||||
|
||||
if (PyObject_HasAttrString(obj, property_name)) {
|
||||
result = PyObject_GetAttrString(obj, property_name);
|
||||
if (result != NULL) {
|
||||
success = true;
|
||||
} else {
|
||||
PyErr_Clear();
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
if (!success) {
|
||||
if (PyMapping_HasKeyString(obj, property_name)) {
|
||||
result = PyMapping_GetItemString(obj, property_name);
|
||||
if (result != NULL) {
|
||||
success = true;
|
||||
} else {
|
||||
PyErr_Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!success) {
|
||||
result = NULL;
|
||||
}
|
||||
}
|
||||
|
|
@ -693,26 +772,8 @@ py_request_func(PyObject *args) {
|
|||
TiXmlElement *xobject = pyobj_to_xml(object);
|
||||
xobject->SetValue("object");
|
||||
xrequest->LinkEndChild(xobject);
|
||||
|
||||
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);
|
||||
}
|
||||
TiXmlElement *xvalue = pyobj_to_xml(value);
|
||||
xrequest->LinkEndChild(xvalue);
|
||||
|
||||
write_xml(_pipe_write, &doc, nout);
|
||||
|
||||
|
|
@ -1045,6 +1106,71 @@ pyobj_to_xml(PyObject *value) {
|
|||
xvalue->SetAttribute("value", str);
|
||||
}
|
||||
|
||||
} else if (PyTuple_Check(value)) {
|
||||
// An immutable sequence. Pass it as a concrete.
|
||||
xvalue->SetAttribute("type", "concrete_sequence");
|
||||
|
||||
Py_ssize_t length = PySequence_Length(value);
|
||||
for (Py_ssize_t i = 0; i < length; ++i) {
|
||||
PyObject *item = PySequence_GetItem(value, i);
|
||||
if (item != NULL) {
|
||||
xvalue->LinkEndChild(pyobj_to_xml(item));
|
||||
Py_DECREF(item);
|
||||
}
|
||||
}
|
||||
|
||||
} else if (PyObject_IsInstance(value, _concrete_struct_class)) {
|
||||
// This is a ConcreteStruct.
|
||||
xvalue->SetAttribute("type", "concrete_struct");
|
||||
|
||||
PyObject *items = PyObject_CallMethod(value, (char *)"getConcreteProperties", (char *)"");
|
||||
if (items == NULL) {
|
||||
PyErr_Print();
|
||||
return xvalue;
|
||||
}
|
||||
|
||||
Py_ssize_t length = PySequence_Length(items);
|
||||
for (Py_ssize_t i = 0; i < length; ++i) {
|
||||
PyObject *item = PySequence_GetItem(items, i);
|
||||
if (item != NULL) {
|
||||
PyObject *a = PySequence_GetItem(item, 0);
|
||||
if (a != NULL) {
|
||||
PyObject *b = PySequence_GetItem(item, 1);
|
||||
if (b != NULL) {
|
||||
TiXmlElement *xitem = pyobj_to_xml(b);
|
||||
Py_DECREF(b);
|
||||
|
||||
PyObject *as_str;
|
||||
if (PyUnicode_Check(a)) {
|
||||
// The key is a unicode value.
|
||||
as_str = PyUnicode_AsUTF8String(a);
|
||||
} else {
|
||||
// The key is a string value or something else. Make it
|
||||
// a string.
|
||||
as_str = PyObject_Str(a);
|
||||
}
|
||||
char *buffer;
|
||||
Py_ssize_t length;
|
||||
if (PyString_AsStringAndSize(as_str, &buffer, &length) != -1) {
|
||||
string str(buffer, length);
|
||||
xitem->SetAttribute("key", str);
|
||||
}
|
||||
Py_DECREF(as_str);
|
||||
|
||||
xvalue->LinkEndChild(xitem);
|
||||
}
|
||||
Py_DECREF(a);
|
||||
}
|
||||
Py_DECREF(item);
|
||||
}
|
||||
}
|
||||
|
||||
// We've already avoided errors in the above code; clear the error
|
||||
// flag.
|
||||
PyErr_Clear();
|
||||
|
||||
Py_DECREF(items);
|
||||
|
||||
} else if (PyObject_IsInstance(value, _undefined_object_class)) {
|
||||
// This is an UndefinedObject.
|
||||
xvalue->SetAttribute("type", "undefined");
|
||||
|
|
@ -1139,6 +1265,44 @@ xml_to_pyobj(TiXmlElement *xvalue) {
|
|||
_runner, object_id);
|
||||
}
|
||||
|
||||
} else if (strcmp(type, "concrete_sequence") == 0) {
|
||||
// Receive a concrete sequence as a tuple.
|
||||
PyObject *list = PyList_New(0);
|
||||
|
||||
TiXmlElement *xitem = xvalue->FirstChildElement("value");
|
||||
while (xitem != NULL) {
|
||||
PyObject *item = xml_to_pyobj(xitem);
|
||||
if (item != NULL) {
|
||||
PyList_Append(list, item);
|
||||
Py_DECREF(item);
|
||||
}
|
||||
xitem = xitem->NextSiblingElement("value");
|
||||
}
|
||||
|
||||
PyObject *result = PyList_AsTuple(list);
|
||||
Py_DECREF(list);
|
||||
return result;
|
||||
|
||||
} else if (strcmp(type, "concrete_struct") == 0) {
|
||||
// Receive a concrete struct as a new ConcreteStruct instance.
|
||||
PyObject *obj = PyObject_CallFunction(_concrete_struct_class, (char *)"");
|
||||
|
||||
if (obj != NULL) {
|
||||
TiXmlElement *xitem = xvalue->FirstChildElement("value");
|
||||
while (xitem != NULL) {
|
||||
const char *key = xitem->Attribute("key");
|
||||
if (key != NULL) {
|
||||
PyObject *item = xml_to_pyobj(xitem);
|
||||
if (item != NULL) {
|
||||
PyObject_SetAttrString(obj, key, item);
|
||||
Py_DECREF(item);
|
||||
}
|
||||
}
|
||||
xitem = xitem->NextSiblingElement("value");
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
} else if (strcmp(type, "python") == 0) {
|
||||
int object_id;
|
||||
if (xvalue->QueryIntAttribute("object_id", &object_id) == TIXML_SUCCESS) {
|
||||
|
|
|
|||
|
|
@ -114,6 +114,7 @@ private:
|
|||
PyObject *_runner;
|
||||
PyObject *_undefined_object_class;
|
||||
PyObject *_undefined;
|
||||
PyObject *_concrete_struct_class;
|
||||
PyObject *_browser_object_class;
|
||||
PyObject *_taskMgr;
|
||||
|
||||
|
|
|
|||
|
|
@ -22,6 +22,8 @@
|
|||
#include "p3dIntObject.h"
|
||||
#include "p3dFloatObject.h"
|
||||
#include "p3dPythonObject.h"
|
||||
#include "p3dConcreteSequence.h"
|
||||
#include "p3dConcreteStruct.h"
|
||||
#include "binaryXml.h"
|
||||
|
||||
#ifndef _WIN32
|
||||
|
|
@ -387,6 +389,35 @@ xml_to_p3dobj(const TiXmlElement *xvalue) {
|
|||
return new P3DStringObject(*value);
|
||||
}
|
||||
|
||||
} else if (strcmp(type, "concrete_sequence") == 0) {
|
||||
P3DConcreteSequence *obj = new P3DConcreteSequence;
|
||||
const TiXmlElement *xitem = xvalue->FirstChildElement("value");
|
||||
while (xitem != NULL) {
|
||||
P3D_object *item = xml_to_p3dobj(xitem);
|
||||
if (item != NULL) {
|
||||
obj->append(item);
|
||||
P3D_OBJECT_DECREF(item);
|
||||
}
|
||||
xitem = xitem->NextSiblingElement("value");
|
||||
}
|
||||
return obj;
|
||||
|
||||
} else if (strcmp(type, "concrete_struct") == 0) {
|
||||
P3DConcreteStruct *obj = new P3DConcreteStruct;
|
||||
const TiXmlElement *xitem = xvalue->FirstChildElement("value");
|
||||
while (xitem != NULL) {
|
||||
const char *key = xitem->Attribute("key");
|
||||
if (key != NULL) {
|
||||
P3D_object *item = xml_to_p3dobj(xitem);
|
||||
if (item != NULL) {
|
||||
obj->set_property(key, item);
|
||||
P3D_OBJECT_DECREF(item);
|
||||
}
|
||||
}
|
||||
xitem = xitem->NextSiblingElement("value");
|
||||
}
|
||||
return obj;
|
||||
|
||||
} else if (strcmp(type, "browser") == 0) {
|
||||
int object_id;
|
||||
if (xvalue->QueryIntAttribute("object_id", &object_id) == TIXML_SUCCESS) {
|
||||
|
|
@ -461,21 +492,21 @@ p3dobj_to_xml(P3D_object *obj) {
|
|||
break;
|
||||
|
||||
case P3D_OT_object:
|
||||
if (obj->_class == &P3DObject::_object_class &&
|
||||
((P3DObject *)obj)->is_python_object() &&
|
||||
((P3DPythonObject *)obj)->get_session() == this) {
|
||||
// If it's one of our kind of objects, it must be a
|
||||
// P3DPythonObject. In this case, just send the object_id down,
|
||||
// since the actual implementation of this object exists (as a
|
||||
// Python object) in the sub-process space.
|
||||
int object_id = ((P3DPythonObject *)obj)->get_object_id();
|
||||
xvalue->SetAttribute("type", "python");
|
||||
xvalue->SetAttribute("object_id", object_id);
|
||||
P3DObject *p3dobj = NULL;
|
||||
if (obj->_class == &P3DObject::_object_class) {
|
||||
p3dobj = (P3DObject *)obj;
|
||||
}
|
||||
|
||||
if (p3dobj != NULL && p3dobj->fill_xml(xvalue, this)) {
|
||||
// This object has a specialized XML representation, valid for
|
||||
// this particular session. It has already been filled into
|
||||
// xvalue.
|
||||
|
||||
} else {
|
||||
// Otherwise, it must a host-provided object, which means we
|
||||
// should pass a reference down to this particular object, so
|
||||
// the Python process knows to call back up to here to query it.
|
||||
// Otherwise, it must a host-provided object, or a Python object
|
||||
// from another session; which means we should pass a reference
|
||||
// down to this particular object, so the Python process knows
|
||||
// to call back up to here to query it.
|
||||
|
||||
P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
|
||||
int object_id = inst_mgr->get_unique_id();
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
#include "p3d_plugin.cxx"
|
||||
#include "p3dBoolObject.cxx"
|
||||
#include "p3dConcreteSequence.cxx"
|
||||
#include "p3dConcreteStruct.cxx"
|
||||
#include "p3dConditionVar.cxx"
|
||||
#include "p3dDownload.cxx"
|
||||
#include "p3dFileDownload.cxx"
|
||||
|
|
|
|||
|
|
@ -58,13 +58,11 @@ make_new(PPInstance *inst, P3D_object *p3d_object) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void PPPandaObject::
|
||||
set_p3d_object(P3D_object *p3d_object) {
|
||||
if (_p3d_object != p3d_object) {
|
||||
P3D_OBJECT_XDECREF(_p3d_object);
|
||||
_p3d_object = p3d_object;
|
||||
if (_p3d_object != NULL) {
|
||||
P3D_OBJECT_INCREF(_p3d_object);
|
||||
}
|
||||
if (p3d_object != NULL) {
|
||||
P3D_OBJECT_INCREF(p3d_object);
|
||||
}
|
||||
P3D_OBJECT_XDECREF(_p3d_object);
|
||||
_p3d_object = p3d_object;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -26,6 +26,10 @@ from pandac.PandaModules import VirtualFileSystem, Filename, Multifile, loadPrcF
|
|||
from direct.stdpy import file
|
||||
from direct.task.TaskManagerGlobal import taskMgr
|
||||
from direct.showbase import AppRunnerGlobal
|
||||
|
||||
# These imports are read by the C++ wrapper in p3dPythonRun.cxx.
|
||||
from direct.showutil.JavaScript import UndefinedObject, Undefined, ConcreteStruct, BrowserObject
|
||||
|
||||
import os
|
||||
import types
|
||||
import __builtin__
|
||||
|
|
@ -60,9 +64,8 @@ class AppRunner(DirectObject):
|
|||
self.windowOpened = False
|
||||
self.windowPrc = None
|
||||
|
||||
# Store this Undefined instance where the application can easily
|
||||
# get to it.
|
||||
self.Undefined = Undefined
|
||||
self.ConcreteStruct = ConcreteStruct
|
||||
|
||||
# This is per session.
|
||||
self.nextScriptId = 0
|
||||
|
|
@ -457,234 +460,6 @@ class AppRunner(DirectObject):
|
|||
|
||||
return (osFilename, tokens)
|
||||
|
||||
class UndefinedObject:
|
||||
""" This is a special object that is returned by the browser to
|
||||
represent a NULL pointer, typically the return value for a failed
|
||||
operation. It has no attributes, similar to None. """
|
||||
|
||||
def __nonzero__(self):
|
||||
return False
|
||||
|
||||
def __str__(self):
|
||||
return "Undefined"
|
||||
|
||||
# In fact, we normally always return this precise instance of the
|
||||
# UndefinedObject.
|
||||
Undefined = UndefinedObject()
|
||||
|
||||
class BrowserObject:
|
||||
""" This class provides the Python wrapper around some object that
|
||||
actually exists in the plugin host's namespace, e.g. a JavaScript
|
||||
or DOM object. """
|
||||
|
||||
def __init__(self, runner, objectId):
|
||||
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 __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:
|
||||
# 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):
|
||||
try:
|
||||
parentObj, attribName = self.__boundMethod
|
||||
if parentObj:
|
||||
# Call it as a method.
|
||||
needsResponse = True
|
||||
if parentObj is self.__runner.dom and attribName == 'alert':
|
||||
# As a special hack, we don't wait for the return
|
||||
# value from the alert() call, since this is a
|
||||
# blocking call, and waiting for this could cause
|
||||
# problems.
|
||||
needsResponse = False
|
||||
|
||||
if parentObj is self.__runner.dom and attribName == 'eval' and len(args) == 1 and isinstance(args[0], types.StringTypes):
|
||||
# As another special hack, we make dom.eval() a
|
||||
# special case, and map it directly into an eval()
|
||||
# call. If the string begins with 'void ', we further
|
||||
# assume we're not waiting for a response.
|
||||
if args[0].startswith('void '):
|
||||
needsResponse = False
|
||||
result = self.__runner.scriptRequest('eval', parentObj, value = args[0], needsResponse = needsResponse)
|
||||
else:
|
||||
# This is a normal method call.
|
||||
try:
|
||||
result = self.__runner.scriptRequest('call', parentObj, propertyName = attribName, value = args, needsResponse = needsResponse)
|
||||
except EnvironmentError:
|
||||
# Problem on the call. Maybe no such method?
|
||||
raise AttributeError
|
||||
else:
|
||||
# Call it as a plain function.
|
||||
result = self.__runner.scriptRequest('call', self, value = args)
|
||||
except EnvironmentError:
|
||||
# Some odd problem on the call.
|
||||
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
|
||||
under the hood. """
|
||||
|
||||
try:
|
||||
value = self.__runner.scriptRequest('get_property', self,
|
||||
propertyName = name)
|
||||
except EnvironmentError:
|
||||
# Failed to retrieve the attribute. But maybe there's a
|
||||
# method instead?
|
||||
if self.__runner.scriptRequest('has_method', self, propertyName = name):
|
||||
# Yes, so create a method wrapper for it.
|
||||
return MethodWrapper(self.__runner, self, 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
|
||||
|
||||
def __setattr__(self, name, value):
|
||||
if name in self.__dict__:
|
||||
self.__dict__[name] = value
|
||||
return
|
||||
|
||||
result = self.__runner.scriptRequest('set_property', self,
|
||||
propertyName = name,
|
||||
value = value)
|
||||
if not result:
|
||||
raise AttributeError(name)
|
||||
|
||||
def __delattr__(self, name):
|
||||
if name in self.__dict__:
|
||||
del self.__dict__[name]
|
||||
return
|
||||
|
||||
result = self.__runner.scriptRequest('del_property', self,
|
||||
propertyName = name)
|
||||
if not result:
|
||||
raise AttributeError(name)
|
||||
|
||||
def __getitem__(self, key):
|
||||
""" Remaps attempts to query an attribute, as in obj['attr'],
|
||||
into the appropriate calls to query the actual browser object
|
||||
under the hood. Following the JavaScript convention, we treat
|
||||
obj['attr'] almost the same as obj.attr. """
|
||||
|
||||
try:
|
||||
value = self.__runner.scriptRequest('get_property', self,
|
||||
propertyName = str(key))
|
||||
except EnvironmentError:
|
||||
# Failed to retrieve the property. We return IndexError
|
||||
# for numeric keys so we can properly support Python's
|
||||
# iterators, but we return KeyError for string keys to
|
||||
# emulate mapping objects.
|
||||
if isinstance(key, types.StringTypes):
|
||||
raise KeyError(key)
|
||||
else:
|
||||
raise IndexError(key)
|
||||
|
||||
return value
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
result = self.__runner.scriptRequest('set_property', self,
|
||||
propertyName = str(key),
|
||||
value = value)
|
||||
if not result:
|
||||
if isinstance(key, types.StringTypes):
|
||||
raise KeyError(key)
|
||||
else:
|
||||
raise IndexError(key)
|
||||
|
||||
def __delitem__(self, key):
|
||||
result = self.__runner.scriptRequest('del_property', self,
|
||||
propertyName = str(key))
|
||||
if not result:
|
||||
if isinstance(key, types.StringTypes):
|
||||
raise KeyError(key)
|
||||
else:
|
||||
raise IndexError(key)
|
||||
|
||||
class MethodWrapper:
|
||||
""" This is a Python wrapper around a property of a BrowserObject
|
||||
that doesn't appear to be a first-class object in the Python
|
||||
sense, but is nonetheless a callable method. """
|
||||
|
||||
def __init__(self, runner, parentObj, objectId):
|
||||
self.__dict__['_MethodWrapper__runner'] = runner
|
||||
self.__dict__['_MethodWraper__boundMethod'] = (parentObj, objectId)
|
||||
|
||||
def __str__(self):
|
||||
parentObj, attribName = self.__boundMethod
|
||||
return "%s.%s" % (parentObj, attribName)
|
||||
|
||||
def __nonzero__(self):
|
||||
return True
|
||||
|
||||
def __call__(self, *args):
|
||||
try:
|
||||
parentObj, attribName = self.__boundMethod
|
||||
# Call it as a method.
|
||||
needsResponse = True
|
||||
if parentObj is self.__runner.dom and attribName == 'alert':
|
||||
# As a special hack, we don't wait for the return
|
||||
# value from the alert() call, since this is a
|
||||
# blocking call, and waiting for this could cause
|
||||
# problems.
|
||||
needsResponse = False
|
||||
|
||||
if parentObj is self.__runner.dom and attribName == 'eval' and len(args) == 1 and isinstance(args[0], types.StringTypes):
|
||||
# As another special hack, we make dom.eval() a
|
||||
# special case, and map it directly into an eval()
|
||||
# call. If the string begins with 'void ', we further
|
||||
# assume we're not waiting for a response.
|
||||
if args[0].startswith('void '):
|
||||
needsResponse = False
|
||||
result = self.__runner.scriptRequest('eval', parentObj, value = args[0], needsResponse = needsResponse)
|
||||
else:
|
||||
# This is a normal method call.
|
||||
try:
|
||||
result = self.__runner.scriptRequest('call', parentObj, propertyName = attribName, value = args, needsResponse = needsResponse)
|
||||
except EnvironmentError:
|
||||
# Problem on the call. Maybe no such method?
|
||||
raise AttributeError
|
||||
|
||||
except EnvironmentError:
|
||||
# Some odd problem on the call.
|
||||
raise TypeError
|
||||
|
||||
return result
|
||||
|
||||
def __setattr__(self, name, value):
|
||||
""" setattr will generally fail on method objects. """
|
||||
raise AttributeError(name)
|
||||
|
||||
def __delattr__(self, name):
|
||||
""" delattr will generally fail on method objects. """
|
||||
raise AttributeError(name)
|
||||
|
||||
if __name__ == '__main__':
|
||||
runner = AppRunner(0)
|
||||
runner.gotWindow = True
|
||||
|
|
|
|||
Loading…
Reference in New Issue