firefox fixes

This commit is contained in:
David Rose 2009-07-11 03:51:01 +00:00
parent 4ee298e942
commit 4dd7ebec82
10 changed files with 128 additions and 39 deletions

View File

@ -37,8 +37,6 @@ typedef P3DSplashWindow SplashWindowType;
#endif #endif
#endif #endif
int P3DInstance::_next_instance_id = 0;
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: P3DInstance::Constructor // Function: P3DInstance::Constructor
// Access: Public // Access: Public
@ -55,8 +53,8 @@ P3DInstance(P3D_request_ready_func *func, void *user_data) :
_got_fparams = false; _got_fparams = false;
_got_wparams = false; _got_wparams = false;
_instance_id = _next_instance_id; P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
++_next_instance_id; _instance_id = inst_mgr->get_unique_id();
INIT_LOCK(_request_lock); INIT_LOCK(_request_lock);
@ -123,7 +121,7 @@ set_fparams(const P3DFileParams &fparams) {
// For the moment, all sessions will be unique. // For the moment, all sessions will be unique.
P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
ostringstream strm; ostringstream strm;
strm << inst_mgr->get_unique_session_index(); strm << inst_mgr->get_unique_id();
_session_key = strm.str(); _session_key = strm.str();
// TODO. // TODO.
@ -457,8 +455,8 @@ void P3DInstance::
start_download(P3DDownload *download) { start_download(P3DDownload *download) {
assert(download->get_download_id() == 0); assert(download->get_download_id() == 0);
int download_id = _next_instance_id; P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
++_next_instance_id; int download_id = inst_mgr->get_unique_id();
download->set_download_id(download_id); download->set_download_id(download_id);
bool inserted = _downloads.insert(Downloads::value_type(download_id, download)).second; bool inserted = _downloads.insert(Downloads::value_type(download_id, download)).second;

View File

@ -139,8 +139,6 @@ private:
typedef deque<P3D_request *> BakedRequests; typedef deque<P3D_request *> BakedRequests;
BakedRequests _baked_requests; BakedRequests _baked_requests;
static int _next_instance_id;
friend class P3DSession; friend class P3DSession;
friend class SplashDownload; friend class SplashDownload;
}; };

View File

@ -40,7 +40,7 @@ P3DInstanceManager *P3DInstanceManager::_global_ptr;
P3DInstanceManager:: P3DInstanceManager::
P3DInstanceManager() { P3DInstanceManager() {
_is_initialized = false; _is_initialized = false;
_unique_session_index = 0; _unique_id = 0;
_notify_thread_continue = false; _notify_thread_continue = false;
_started_notify_thread = 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 // Access: Public
// Description: Returns a number used to uniquify the session_key for // Description: Returns a number used to uniquify different
// different instances. This number is guaranteed to be // instances. This number is guaranteed to be different
// different at each call. // at each call, at least until the int space rolls
// over.
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
int P3DInstanceManager:: int P3DInstanceManager::
get_unique_session_index() { get_unique_id() {
++_unique_session_index; ++_unique_id;
return _unique_session_index; return _unique_id;
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////

View File

@ -61,7 +61,7 @@ public:
inline int get_num_instances() const; inline int get_num_instances() const;
int get_unique_session_index(); int get_unique_id();
void signal_request_ready(P3DInstance *inst); void signal_request_ready(P3DInstance *inst);
P3D_class_definition *make_class_definition() const; P3D_class_definition *make_class_definition() const;
@ -100,7 +100,7 @@ private:
typedef map<string, P3DPackage *> Packages; typedef map<string, P3DPackage *> Packages;
Packages _packages; Packages _packages;
int _unique_session_index; int _unique_id;
// This condition var is waited on the main thread and signaled in a // This condition var is waited on the main thread and signaled in a
// sub-thread when new request notices arrive. // sub-thread when new request notices arrive.

View File

@ -32,6 +32,7 @@ P3DPythonRun(int argc, char *argv[]) {
INIT_LOCK(_commands_lock); INIT_LOCK(_commands_lock);
INIT_THREAD(_read_thread); INIT_THREAD(_read_thread);
_session_id = 0;
_next_sent_id = 0; _next_sent_id = 0;
_program_name = argv[0]; _program_name = argv[0];
@ -223,7 +224,20 @@ handle_command(TiXmlDocument *doc) {
const char *cmd = xcommand->Attribute("cmd"); const char *cmd = xcommand->Attribute("cmd");
if (cmd != NULL) { 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); assert(!needs_response);
TiXmlElement *xinstance = xcommand->FirstChildElement("instance"); TiXmlElement *xinstance = xcommand->FirstChildElement("instance");
if (xinstance != (TiXmlElement *)NULL) { if (xinstance != (TiXmlElement *)NULL) {
@ -405,6 +419,7 @@ handle_pyobj_command(TiXmlElement *xcommand, bool needs_response,
if (PyArg_ParseTuple(params, "s", &property_name)) { if (PyArg_ParseTuple(params, "s", &property_name)) {
if (PyObject_HasAttrString(obj, property_name)) { if (PyObject_HasAttrString(obj, property_name)) {
result = PyObject_GetAttrString(obj, property_name); result = PyObject_GetAttrString(obj, property_name);
} else { } else {
result = NULL; result = NULL;
} }

View File

@ -105,6 +105,8 @@ private:
typedef pmap<int, P3DCInstance *> Instances; typedef pmap<int, P3DCInstance *> Instances;
Instances _instances; Instances _instances;
int _session_id;
string _program_name; string _program_name;
int _py_argc; int _py_argc;
char **_py_argv; char **_py_argv;

View File

@ -38,13 +38,12 @@
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
P3DSession:: P3DSession::
P3DSession(P3DInstance *inst) { P3DSession(P3DInstance *inst) {
P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
_session_id = inst_mgr->get_unique_id();
_session_key = inst->get_session_key(); _session_key = inst->get_session_key();
_python_version = inst->get_python_version(); _python_version = inst->get_python_version();
_next_sent_id = 0;
_p3dpython_running = false; _p3dpython_running = false;
_next_response_id = 0;
_response = NULL; _response = NULL;
_got_response_id = -1; _got_response_id = -1;
@ -58,8 +57,6 @@ P3DSession(P3DInstance *inst) {
INIT_LOCK(_instances_lock); INIT_LOCK(_instances_lock);
INIT_THREAD(_read_thread); INIT_THREAD(_read_thread);
P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
_panda3d = inst_mgr->get_package("panda3d", "dev", "Panda3D"); _panda3d = inst_mgr->get_package("panda3d", "dev", "Panda3D");
_python_root_dir = _panda3d->get_package_dir(); _python_root_dir = _panda3d->get_package_dir();
inst->add_package(_panda3d); inst->add_package(_panda3d);
@ -261,8 +258,8 @@ command_and_response(TiXmlDocument *command) {
return NULL; return NULL;
} }
int response_id = _next_response_id; P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
++_next_response_id; int response_id = inst_mgr->get_unique_id();
// Add the "want_response_id" attribute to the toplevel command, so // Add the "want_response_id" attribute to the toplevel command, so
// the sub-process knows we'll be waiting for its response. // 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 // should pass a reference down to this particular object, so
// the Python process knows to call back up to here to query it. // the Python process knows to call back up to here to query it.
int object_id = _next_sent_id; P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
++_next_sent_id; int object_id = inst_mgr->get_unique_id();
bool inserted = _sent_objects.insert(SentObjects::value_type(object_id, obj)).second; bool inserted = _sent_objects.insert(SentObjects::value_type(object_id, obj)).second;
while (!inserted) { while (!inserted) {
// Hmm, we must have cycled around the entire int space? Either // Hmm, we must have cycled around the entire int space? Either
// that, or there's a logic bug somewhere. Assume the former, // that, or there's a logic bug somewhere. Assume the former,
// and keep looking for an empty slot. // and keep looking for an empty slot.
object_id = _next_sent_id; object_id = inst_mgr->get_unique_id();
++_next_sent_id;
inserted = _sent_objects.insert(SentObjects::value_type(object_id, obj)).second; inserted = _sent_objects.insert(SentObjects::value_type(object_id, obj)).second;
} }
@ -656,16 +652,28 @@ start_p3dpython() {
spawn_read_thread(); spawn_read_thread();
// Now that the process has been started, feed it any commands we // The very first command we send to the process is its session_id.
// may have queued up. 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; Commands::iterator ci;
for (ci = _commands.begin(); ci != _commands.end(); ++ci) { for (ci = _commands.begin(); ci != _commands.end(); ++ci) {
nout << "sent: " << *(*ci) << "\n" << flush; nout << "sent: " << *(*ci) << "\n" << flush;
_pipe_write << *(*ci); _pipe_write << *(*ci);
delete (*ci); delete (*ci);
} }
_pipe_write << flush;
_commands.clear(); _commands.clear();
_pipe_write << flush;
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////

View File

@ -98,6 +98,7 @@ private:
}; };
private: private:
int _session_id;
string _session_key; string _session_key;
string _python_version; string _python_version;
string _output_filename; string _output_filename;
@ -119,7 +120,6 @@ private:
// child process tells us it's safe to delete them. // child process tells us it's safe to delete them.
typedef map<int, P3D_object *> SentObjects; typedef map<int, P3D_object *> SentObjects;
SentObjects _sent_objects; SentObjects _sent_objects;
int _next_sent_id;
P3DPackage *_panda3d; P3DPackage *_panda3d;
PackageCallback *_panda3d_callback; PackageCallback *_panda3d_callback;
@ -132,8 +132,6 @@ private:
#endif #endif
bool _p3dpython_running; bool _p3dpython_running;
int _next_response_id;
// The _response_ready mutex protects this pointer. // The _response_ready mutex protects this pointer.
TiXmlDocument *_response; TiXmlDocument *_response;
int _got_response_id; int _got_response_id;

View File

@ -221,7 +221,13 @@ has_property(NPIdentifier name) {
// will never be called. So we always say we *do* have any // will never be called. So we always say we *do* have any
// particular property, whether we currently have it right now or // particular property, whether we currently have it right now or
// not (since we *could* have it if you call set_property()). // 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;
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////

View File

@ -518,7 +518,12 @@ class BrowserObject:
value = self.__runner.scriptRequest('get_property', self, value = self.__runner.scriptRequest('get_property', self,
propertyName = name) propertyName = name)
except EnvironmentError: 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) raise AttributeError(name)
if isinstance(value, BrowserObject): if isinstance(value, BrowserObject):
@ -591,6 +596,64 @@ class BrowserObject:
else: else:
raise IndexError(key) 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__': if __name__ == '__main__':
runner = AppRunner() runner = AppRunner()
runner.gotWindow = True runner.gotWindow = True