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
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;

View File

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

View File

@ -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;
}
////////////////////////////////////////////////////////////////////

View File

@ -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.

View File

@ -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;
}

View File

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

View File

@ -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;
}
////////////////////////////////////////////////////////////////////

View File

@ -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;

View File

@ -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;
}
////////////////////////////////////////////////////////////////////

View File

@ -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