mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-02 09:52:27 -04:00
firefox fixes
This commit is contained in:
parent
4ee298e942
commit
4dd7ebec82
@ -37,8 +37,6 @@ typedef P3DSplashWindow SplashWindowType;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
int P3DInstance::_next_instance_id = 0;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DInstance::Constructor
|
||||
// Access: Public
|
||||
@ -55,8 +53,8 @@ P3DInstance(P3D_request_ready_func *func, void *user_data) :
|
||||
_got_fparams = false;
|
||||
_got_wparams = false;
|
||||
|
||||
_instance_id = _next_instance_id;
|
||||
++_next_instance_id;
|
||||
P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
|
||||
_instance_id = inst_mgr->get_unique_id();
|
||||
|
||||
INIT_LOCK(_request_lock);
|
||||
|
||||
@ -123,7 +121,7 @@ set_fparams(const P3DFileParams &fparams) {
|
||||
// For the moment, all sessions will be unique.
|
||||
P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
|
||||
ostringstream strm;
|
||||
strm << inst_mgr->get_unique_session_index();
|
||||
strm << inst_mgr->get_unique_id();
|
||||
_session_key = strm.str();
|
||||
|
||||
// TODO.
|
||||
@ -457,8 +455,8 @@ void P3DInstance::
|
||||
start_download(P3DDownload *download) {
|
||||
assert(download->get_download_id() == 0);
|
||||
|
||||
int download_id = _next_instance_id;
|
||||
++_next_instance_id;
|
||||
P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
|
||||
int download_id = inst_mgr->get_unique_id();
|
||||
download->set_download_id(download_id);
|
||||
|
||||
bool inserted = _downloads.insert(Downloads::value_type(download_id, download)).second;
|
||||
|
@ -139,8 +139,6 @@ private:
|
||||
typedef deque<P3D_request *> BakedRequests;
|
||||
BakedRequests _baked_requests;
|
||||
|
||||
static int _next_instance_id;
|
||||
|
||||
friend class P3DSession;
|
||||
friend class SplashDownload;
|
||||
};
|
||||
|
@ -40,7 +40,7 @@ P3DInstanceManager *P3DInstanceManager::_global_ptr;
|
||||
P3DInstanceManager::
|
||||
P3DInstanceManager() {
|
||||
_is_initialized = false;
|
||||
_unique_session_index = 0;
|
||||
_unique_id = 0;
|
||||
|
||||
_notify_thread_continue = false;
|
||||
_started_notify_thread = false;
|
||||
@ -280,16 +280,17 @@ get_package(const string &package_name, const string &package_version,
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DInstanceManager::get_unique_session_index
|
||||
// Function: P3DInstanceManager::get_unique_id
|
||||
// Access: Public
|
||||
// Description: Returns a number used to uniquify the session_key for
|
||||
// different instances. This number is guaranteed to be
|
||||
// different at each call.
|
||||
// Description: Returns a number used to uniquify different
|
||||
// instances. This number is guaranteed to be different
|
||||
// at each call, at least until the int space rolls
|
||||
// over.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
int P3DInstanceManager::
|
||||
get_unique_session_index() {
|
||||
++_unique_session_index;
|
||||
return _unique_session_index;
|
||||
get_unique_id() {
|
||||
++_unique_id;
|
||||
return _unique_id;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
@ -61,7 +61,7 @@ public:
|
||||
|
||||
inline int get_num_instances() const;
|
||||
|
||||
int get_unique_session_index();
|
||||
int get_unique_id();
|
||||
void signal_request_ready(P3DInstance *inst);
|
||||
|
||||
P3D_class_definition *make_class_definition() const;
|
||||
@ -100,7 +100,7 @@ private:
|
||||
typedef map<string, P3DPackage *> Packages;
|
||||
Packages _packages;
|
||||
|
||||
int _unique_session_index;
|
||||
int _unique_id;
|
||||
|
||||
// This condition var is waited on the main thread and signaled in a
|
||||
// sub-thread when new request notices arrive.
|
||||
|
@ -32,6 +32,7 @@ P3DPythonRun(int argc, char *argv[]) {
|
||||
INIT_LOCK(_commands_lock);
|
||||
INIT_THREAD(_read_thread);
|
||||
|
||||
_session_id = 0;
|
||||
_next_sent_id = 0;
|
||||
|
||||
_program_name = argv[0];
|
||||
@ -223,7 +224,20 @@ handle_command(TiXmlDocument *doc) {
|
||||
|
||||
const char *cmd = xcommand->Attribute("cmd");
|
||||
if (cmd != NULL) {
|
||||
if (strcmp(cmd, "start_instance") == 0) {
|
||||
if (strcmp(cmd, "init") == 0) {
|
||||
assert(!needs_response);
|
||||
|
||||
// The only purpose of the "init" command is to send us a
|
||||
// unique session ID, which in fact we don't do much with.
|
||||
xcommand->Attribute("session_id", &_session_id);
|
||||
|
||||
// We do use it to initiate our object id sequence with a
|
||||
// number at least a little bit distinct from other sessions,
|
||||
// though. No technical requirement that we do this, but it
|
||||
// does make debugging the logs a bit easier.
|
||||
_next_sent_id = _session_id * 1000;
|
||||
|
||||
} else if (strcmp(cmd, "start_instance") == 0) {
|
||||
assert(!needs_response);
|
||||
TiXmlElement *xinstance = xcommand->FirstChildElement("instance");
|
||||
if (xinstance != (TiXmlElement *)NULL) {
|
||||
@ -405,6 +419,7 @@ handle_pyobj_command(TiXmlElement *xcommand, bool needs_response,
|
||||
if (PyArg_ParseTuple(params, "s", &property_name)) {
|
||||
if (PyObject_HasAttrString(obj, property_name)) {
|
||||
result = PyObject_GetAttrString(obj, property_name);
|
||||
|
||||
} else {
|
||||
result = NULL;
|
||||
}
|
||||
|
@ -105,6 +105,8 @@ private:
|
||||
typedef pmap<int, P3DCInstance *> Instances;
|
||||
Instances _instances;
|
||||
|
||||
int _session_id;
|
||||
|
||||
string _program_name;
|
||||
int _py_argc;
|
||||
char **_py_argv;
|
||||
|
@ -38,13 +38,12 @@
|
||||
////////////////////////////////////////////////////////////////////
|
||||
P3DSession::
|
||||
P3DSession(P3DInstance *inst) {
|
||||
P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
|
||||
_session_id = inst_mgr->get_unique_id();
|
||||
_session_key = inst->get_session_key();
|
||||
_python_version = inst->get_python_version();
|
||||
|
||||
_next_sent_id = 0;
|
||||
|
||||
_p3dpython_running = false;
|
||||
_next_response_id = 0;
|
||||
_response = NULL;
|
||||
_got_response_id = -1;
|
||||
|
||||
@ -58,8 +57,6 @@ P3DSession(P3DInstance *inst) {
|
||||
INIT_LOCK(_instances_lock);
|
||||
INIT_THREAD(_read_thread);
|
||||
|
||||
P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
|
||||
|
||||
_panda3d = inst_mgr->get_package("panda3d", "dev", "Panda3D");
|
||||
_python_root_dir = _panda3d->get_package_dir();
|
||||
inst->add_package(_panda3d);
|
||||
@ -261,8 +258,8 @@ command_and_response(TiXmlDocument *command) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int response_id = _next_response_id;
|
||||
++_next_response_id;
|
||||
P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
|
||||
int response_id = inst_mgr->get_unique_id();
|
||||
|
||||
// Add the "want_response_id" attribute to the toplevel command, so
|
||||
// the sub-process knows we'll be waiting for its response.
|
||||
@ -474,15 +471,14 @@ p3dobj_to_xml(P3D_object *obj) {
|
||||
// should pass a reference down to this particular object, so
|
||||
// the Python process knows to call back up to here to query it.
|
||||
|
||||
int object_id = _next_sent_id;
|
||||
++_next_sent_id;
|
||||
P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
|
||||
int object_id = inst_mgr->get_unique_id();
|
||||
bool inserted = _sent_objects.insert(SentObjects::value_type(object_id, obj)).second;
|
||||
while (!inserted) {
|
||||
// Hmm, we must have cycled around the entire int space? Either
|
||||
// that, or there's a logic bug somewhere. Assume the former,
|
||||
// and keep looking for an empty slot.
|
||||
object_id = _next_sent_id;
|
||||
++_next_sent_id;
|
||||
object_id = inst_mgr->get_unique_id();
|
||||
inserted = _sent_objects.insert(SentObjects::value_type(object_id, obj)).second;
|
||||
}
|
||||
|
||||
@ -656,16 +652,28 @@ start_p3dpython() {
|
||||
|
||||
spawn_read_thread();
|
||||
|
||||
// Now that the process has been started, feed it any commands we
|
||||
// may have queued up.
|
||||
// The very first command we send to the process is its session_id.
|
||||
TiXmlDocument doc;
|
||||
TiXmlDeclaration *decl = new TiXmlDeclaration("1.0", "utf-8", "");
|
||||
TiXmlElement *xcommand = new TiXmlElement("command");
|
||||
xcommand->SetAttribute("cmd", "init");
|
||||
xcommand->SetAttribute("session_id", _session_id);
|
||||
doc.LinkEndChild(decl);
|
||||
doc.LinkEndChild(xcommand);
|
||||
nout << "sent: " << doc << "\n" << flush;
|
||||
_pipe_write << doc;
|
||||
|
||||
// Also feed it any commands we may have queued up from before the
|
||||
// process was started.
|
||||
Commands::iterator ci;
|
||||
for (ci = _commands.begin(); ci != _commands.end(); ++ci) {
|
||||
nout << "sent: " << *(*ci) << "\n" << flush;
|
||||
_pipe_write << *(*ci);
|
||||
delete (*ci);
|
||||
}
|
||||
_pipe_write << flush;
|
||||
_commands.clear();
|
||||
|
||||
_pipe_write << flush;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
@ -98,6 +98,7 @@ private:
|
||||
};
|
||||
|
||||
private:
|
||||
int _session_id;
|
||||
string _session_key;
|
||||
string _python_version;
|
||||
string _output_filename;
|
||||
@ -119,7 +120,6 @@ private:
|
||||
// child process tells us it's safe to delete them.
|
||||
typedef map<int, P3D_object *> SentObjects;
|
||||
SentObjects _sent_objects;
|
||||
int _next_sent_id;
|
||||
|
||||
P3DPackage *_panda3d;
|
||||
PackageCallback *_panda3d_callback;
|
||||
@ -132,8 +132,6 @@ private:
|
||||
#endif
|
||||
bool _p3dpython_running;
|
||||
|
||||
int _next_response_id;
|
||||
|
||||
// The _response_ready mutex protects this pointer.
|
||||
TiXmlDocument *_response;
|
||||
int _got_response_id;
|
||||
|
@ -221,7 +221,13 @@ has_property(NPIdentifier name) {
|
||||
// will never be called. So we always say we *do* have any
|
||||
// particular property, whether we currently have it right now or
|
||||
// not (since we *could* have it if you call set_property()).
|
||||
return true;
|
||||
|
||||
// On the other hand, Firefox gets confused about methods that are
|
||||
// also properties. So you have to say there's *no* property if
|
||||
// there is in fact a callable method by that name, or Firefox will
|
||||
// never call the method.
|
||||
bool result = P3D_OBJECT_HAS_METHOD(_p3d_object, property_name.c_str());
|
||||
return !result;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
@ -518,7 +518,12 @@ class BrowserObject:
|
||||
value = self.__runner.scriptRequest('get_property', self,
|
||||
propertyName = name)
|
||||
except EnvironmentError:
|
||||
# Failed to retrieve the attribute.
|
||||
# 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):
|
||||
@ -591,6 +596,64 @@ class BrowserObject:
|
||||
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()
|
||||
runner.gotWindow = True
|
||||
|
Loading…
x
Reference in New Issue
Block a user