diff --git a/direct/src/plugin/p3dInstance.cxx b/direct/src/plugin/p3dInstance.cxx index f28099366b..aea4e26b7c 100644 --- a/direct/src/plugin/p3dInstance.cxx +++ b/direct/src/plugin/p3dInstance.cxx @@ -83,6 +83,8 @@ P3DInstance(P3D_request_ready_func *func, // Set some initial properties. _panda_script_object->set_float_property("downloadProgress", 0.0); + _panda_script_object->set_bool_property("downloadComplete", false); + _panda_script_object->set_string_property("status", "initial"); } //////////////////////////////////////////////////////////////////// @@ -166,20 +168,8 @@ set_p3d_filename(const string &p3d_filename) { // Generate a special notification: onpluginload, indicating the // plugin has read its parameters and is ready to be queried (even - // if Python has not yet started). This notification is special - // because it generated at the C++ level, here; most of them are - // generated by the Python code, once that is running. - P3D_request *request = new P3D_request; - request->_request_type = P3D_RT_notify; - request->_request._notify._message = strdup("onpluginload"); - add_baked_request(request); - - // Also eval the HTML associated token. - string expression = _fparams.lookup_token("onpluginload"); - if (!expression.empty() && _browser_script_object != NULL) { - P3D_object *result = P3D_OBJECT_EVAL(_browser_script_object, expression.c_str()); - P3D_OBJECT_XDECREF(result); - } + // if Python has not yet started). + send_notify("onpluginload"); } //////////////////////////////////////////////////////////////////// @@ -321,6 +311,30 @@ get_request() { P3D_request *request = _baked_requests.front(); _baked_requests.pop_front(); _request_pending = !_baked_requests.empty(); + + if (request != NULL) { + if (request->_request_type == P3D_RT_notify) { + // Also eval the associated HTML token, if any. + string message = request->_request._notify._message; + string expression = _fparams.lookup_token(message); + if (!expression.empty() && _browser_script_object != NULL) { + P3D_object *result = P3D_OBJECT_EVAL(_browser_script_object, expression.c_str()); + P3D_OBJECT_XDECREF(result); + } + + } else if (request->_request_type == P3D_RT_stop) { + // We also send an implicit message when Python requests itself + // to shutdown. + _panda_script_object->set_pyobj(NULL); + _panda_script_object->set_string_property("status", "stopped"); + + string expression = _fparams.lookup_token("onpythonstop"); + if (!expression.empty() && _browser_script_object != NULL) { + P3D_object *result = P3D_OBJECT_EVAL(_browser_script_object, expression.c_str()); + P3D_OBJECT_XDECREF(result); + } + } + } return request; } @@ -720,6 +734,7 @@ make_p3d_request(TiXmlElement *xrequest) { if (strcmp(rtype, "notify") == 0) { const char *message = xrequest->Attribute("message"); if (message != NULL) { + // A notify message from Python code. request = new P3D_request; request->_request_type = P3D_RT_notify; request->_request._notify._message = strdup(message); @@ -816,6 +831,8 @@ handle_notify_request(const string &message) { P3D_OBJECT_DECREF(result); } + _panda_script_object->set_string_property("status", "running"); + } else if (message == "onwindowopen") { // The process told us that it just succesfully opened its // window. Tear down the splash window. @@ -825,6 +842,8 @@ handle_notify_request(const string &message) { _splash_window = NULL; } + _panda_script_object->set_string_property("status", "open"); + #ifdef __APPLE__ // Start a timer to update the frame repeatedly. This seems to be // steadier than waiting for nullEvent. @@ -976,6 +995,17 @@ make_splash_window() { start_download(download); } +//////////////////////////////////////////////////////////////////// +// Function: P3DInstance::start_package_download +// Access: Private +// Description: Notified when the package download begins. +//////////////////////////////////////////////////////////////////// +void P3DInstance:: +start_package_download(P3DPackage *package) { + _panda_script_object->set_string_property("status", "downloading"); + send_notify("ondownloadbegin"); +} + //////////////////////////////////////////////////////////////////// // Function: P3DInstance::install_progress // Access: Private @@ -990,6 +1020,40 @@ install_progress(P3DPackage *package, double progress) { _panda_script_object->set_float_property("downloadProgress", progress); } +//////////////////////////////////////////////////////////////////// +// Function: P3DInstance::package_ready +// Access: Private +// Description: Notified when the package is fully downloaded. +//////////////////////////////////////////////////////////////////// +void P3DInstance:: +package_ready(P3DPackage *package, bool success) { + if (success) { + install_progress(package, 1.0); + _panda_script_object->set_bool_property("downloadComplete", true); + _panda_script_object->set_string_property("status", "starting"); + send_notify("ondownloadcomplete"); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: P3DInstance::send_notify +// Access: Private +// Description: Generates a synthetic notify message here at the C++ +// level. +// +// Most notify messages are generated from within the +// Python code, and don't use this method; but a few +// have to be sent before Python has started, and those +// come through this method. +//////////////////////////////////////////////////////////////////// +void P3DInstance:: +send_notify(const string &message) { + P3D_request *request = new P3D_request; + request->_request_type = P3D_RT_notify; + request->_request._notify._message = strdup(message.c_str()); + add_baked_request(request); +} + //////////////////////////////////////////////////////////////////// // Function: P3DInstance::paint_window // Access: Private diff --git a/direct/src/plugin/p3dInstance.h b/direct/src/plugin/p3dInstance.h index 5d01fb7eef..6b53377ae2 100644 --- a/direct/src/plugin/p3dInstance.h +++ b/direct/src/plugin/p3dInstance.h @@ -107,11 +107,15 @@ private: const string &property_name, P3D_object *value, bool needs_response, int unique_id); void make_splash_window(); + void start_package_download(P3DPackage *package); void install_progress(P3DPackage *package, double progress); + void package_ready(P3DPackage *package, bool success); void paint_window(); void add_modifier_flags(unsigned int &swb_flags, int modifiers); + void send_notify(const string &message); + #ifdef __APPLE__ static void timer_callback(CFRunLoopTimerRef timer, void *info); #endif // __APPLE__ diff --git a/direct/src/plugin/p3dSession.cxx b/direct/src/plugin/p3dSession.cxx index 3d94851086..7cbd93c34d 100644 --- a/direct/src/plugin/p3dSession.cxx +++ b/direct/src/plugin/p3dSession.cxx @@ -235,6 +235,7 @@ start_instance(P3DInstance *inst) { _panda3d_callback = new PackageCallback(this); _panda3d->set_callback(_panda3d_callback); } + inst->start_package_download(_panda3d); } } @@ -656,6 +657,33 @@ install_progress(P3DPackage *package, double progress) { } } +//////////////////////////////////////////////////////////////////// +// Function: P3DSession::package_ready +// Access: Private +// Description: Notified when the package is fully downloaded. +//////////////////////////////////////////////////////////////////// +void P3DSession:: +package_ready(P3DPackage *package, bool success) { + _panda3d_callback = NULL; + + Instances::iterator ii; + for (ii = _instances.begin(); ii != _instances.end(); ++ii) { + P3DInstance *inst = (*ii).second; + inst->package_ready(package, success); + } + + if (package == _panda3d) { + if (success) { + start_p3dpython(); + } else { + nout << "Failed to install " << package->get_package_name() + << "_" << package->get_package_version() << "\n"; + } + } else { + nout << "Unexpected panda3d package: " << package << "\n"; + } +} + //////////////////////////////////////////////////////////////////// // Function: P3DSession::start_p3dpython // Access: Private @@ -1092,30 +1120,6 @@ PackageCallback(P3DSession *session) : { } -//////////////////////////////////////////////////////////////////// -// Function: P3DSession::PackageCallback::package_ready -// Access: Public, Virtual -// Description: -//////////////////////////////////////////////////////////////////// -void P3DSession::PackageCallback:: -package_ready(P3DPackage *package, bool success) { - if (this == _session->_panda3d_callback) { - _session->_panda3d_callback = NULL; - if (package == _session->_panda3d) { - if (success) { - _session->start_p3dpython(); - } else { - nout << "Failed to install " << package->get_package_name() - << "_" << package->get_package_version() << "\n"; - } - } else { - nout << "Unexpected panda3d package: " << package << "\n"; - } - } else { - nout << "Unexpected callback for P3DSession\n"; - } -} - //////////////////////////////////////////////////////////////////// // Function: P3DSession::PackageCallback::install_progress // Access: Public, Virtual @@ -1126,5 +1130,21 @@ void P3DSession::PackageCallback:: install_progress(P3DPackage *package, double progress) { if (this == _session->_panda3d_callback) { _session->install_progress(package, progress); + } else { + nout << "Unexpected callback for P3DSession\n"; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: P3DSession::PackageCallback::package_ready +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void P3DSession::PackageCallback:: +package_ready(P3DPackage *package, bool success) { + if (this == _session->_panda3d_callback) { + _session->package_ready(package, success); + } else { + nout << "Unexpected callback for P3DSession\n"; } } diff --git a/direct/src/plugin/p3dSession.h b/direct/src/plugin/p3dSession.h index a1ec296102..6277229215 100644 --- a/direct/src/plugin/p3dSession.h +++ b/direct/src/plugin/p3dSession.h @@ -62,6 +62,7 @@ public: private: void install_progress(P3DPackage *package, double progress); + void package_ready(P3DPackage *package, bool success); void start_p3dpython(); void spawn_read_thread(); diff --git a/direct/src/plugin/p3dToplevelObject.cxx b/direct/src/plugin/p3dToplevelObject.cxx index 4368a4b6eb..e1fb79905d 100644 --- a/direct/src/plugin/p3dToplevelObject.cxx +++ b/direct/src/plugin/p3dToplevelObject.cxx @@ -34,7 +34,7 @@ P3DToplevelObject:: ~P3DToplevelObject() { set_pyobj(NULL); - // Just in case there are properties we haven't cleared yet. + // Clear the local properties. Properties::const_iterator pi; for (pi = _properties.begin(); pi != _properties.end(); ++pi) { P3D_object *value = (*pi).second; @@ -139,32 +139,34 @@ get_property(const string &property) { //////////////////////////////////////////////////////////////////// bool P3DToplevelObject:: set_property(const string &property, P3D_object *value) { - if (_pyobj == NULL) { - // Without a pyobj, we just store the value locally. - if (value != NULL) { - Properties::iterator pi; - pi = _properties.insert(Properties::value_type(property, NULL)).first; - assert(pi != _properties.end()); - P3D_object *orig_value = (*pi).second; - if (orig_value != value) { - P3D_OBJECT_XDECREF(orig_value); - (*pi).second = value; - P3D_OBJECT_INCREF(value); - } - } else { - // Or delete the property locally. - Properties::iterator pi; - pi = _properties.find(property); - if (pi != _properties.end()) { - P3D_object *orig_value = (*pi).second; - P3D_OBJECT_DECREF(orig_value); - _properties.erase(pi); - } + // First, we set the property locally. + if (value != NULL) { + Properties::iterator pi; + pi = _properties.insert(Properties::value_type(property, NULL)).first; + assert(pi != _properties.end()); + P3D_object *orig_value = (*pi).second; + if (orig_value != value) { + P3D_OBJECT_XDECREF(orig_value); + (*pi).second = value; + P3D_OBJECT_INCREF(value); } + } else { + // (Or delete the property locally.) + Properties::iterator pi; + pi = _properties.find(property); + if (pi != _properties.end()) { + P3D_object *orig_value = (*pi).second; + P3D_OBJECT_DECREF(orig_value); + _properties.erase(pi); + } + } + + if (_pyobj == NULL) { + // Without a pyobj, that's all we do. return true; } - // With a pyobj, we pass this request down. + // With a pyobj, we also pass this request down. return P3D_OBJECT_SET_PROPERTY(_pyobj, property.c_str(), value); } @@ -246,9 +248,7 @@ set_pyobj(P3D_object *pyobj) { const string &property_name = (*pi).first; P3D_object *value = (*pi).second; P3D_OBJECT_SET_PROPERTY(_pyobj, property_name.c_str(), value); - P3D_OBJECT_DECREF(value); } - _properties.clear(); } } } diff --git a/direct/src/plugin/p3d_lock.h b/direct/src/plugin/p3d_lock.h index 4646d345f4..12073600c5 100755 --- a/direct/src/plugin/p3d_lock.h +++ b/direct/src/plugin/p3d_lock.h @@ -31,7 +31,7 @@ public: #define LOCK _lock #define INIT_LOCK(lock) { InitializeCriticalSection(&(lock)._l); (lock)._count = 0; } -#define ACQUIRE_LOCK(lock) { EnterCriticalSection(&(lock)._l); ++((lock)._count); if ((lock)._count > 1) { nout << "count = " << (lock)._count << "\n"; } } +#define ACQUIRE_LOCK(lock) { EnterCriticalSection(&(lock)._l); ++((lock)._count); } #define RELEASE_LOCK(lock) { --((lock)._count); LeaveCriticalSection(&(lock)._l); } #define DESTROY_LOCK(lock) DeleteCriticalSection(&(lock)._l) diff --git a/direct/src/plugin_npapi/ppInstance.cxx b/direct/src/plugin_npapi/ppInstance.cxx index 152b6d5ae6..9aed862627 100644 --- a/direct/src/plugin_npapi/ppInstance.cxx +++ b/direct/src/plugin_npapi/ppInstance.cxx @@ -70,13 +70,8 @@ PPInstance(NPMIMEType pluginType, NPP instance, uint16 mode, //////////////////////////////////////////////////////////////////// PPInstance:: ~PPInstance() { -#ifdef _WIN32 - if (_got_window) { - // Restore the parent window to its own window handler. - HWND hwnd = (HWND)_window.window; - SetWindowLongPtr(hwnd, GWL_WNDPROC, _orig_window_proc); - } -#endif // _WIN32 + nout << "Destructing PPInstance\n"; + cleanup_window(); if (_p3d_inst != NULL) { P3D_instance_finish(_p3d_inst); @@ -421,6 +416,7 @@ handle_request(P3D_request *request) { P3D_instance_finish(_p3d_inst); _p3d_inst = NULL; } + cleanup_window(); // Guess the browser doesn't really care. handled = true; break; @@ -1074,9 +1070,29 @@ send_window() { parent_window); } +//////////////////////////////////////////////////////////////////// +// Function: PPInstance::cleanup_window +// Access: Private +// Description: Called at instance shutdown, this restores the parent +// window to its original state. +//////////////////////////////////////////////////////////////////// +void PPInstance:: +cleanup_window() { + if (_got_window) { +#ifdef _WIN32 + // Restore the parent window to its own window handler. + HWND hwnd = (HWND)_window.window; + SetWindowLongPtr(hwnd, GWL_WNDPROC, _orig_window_proc); + nout << "Restored window handler for " << hwnd << "\n"; + InvalidateRect(hwnd, NULL, true); +#endif // _WIN32 + _got_window = false; + } +} + //////////////////////////////////////////////////////////////////// // Function: PPInstance::copy_file -// Access: Public +// Access: Private // Description: Copies the data in the file named by from_filename // into the file named by to_filename. //////////////////////////////////////////////////////////////////// diff --git a/direct/src/plugin_npapi/ppInstance.h b/direct/src/plugin_npapi/ppInstance.h index 92c6ff7a18..9f4a837451 100644 --- a/direct/src/plugin_npapi/ppInstance.h +++ b/direct/src/plugin_npapi/ppInstance.h @@ -78,6 +78,7 @@ private: void create_instance(); void send_window(); + void cleanup_window(); bool copy_file(const string &from_filename, const string &to_filename); static void handle_request_loop(); diff --git a/direct/src/showutil/pfreeze.py b/direct/src/showutil/pfreeze.py index 9cfbaaf978..3046f0749c 100755 --- a/direct/src/showutil/pfreeze.py +++ b/direct/src/showutil/pfreeze.py @@ -78,6 +78,9 @@ for opt, arg in opts: freezer.handleCustomPath(module) elif opt == '-h': usage(0) + else: + print 'illegal option: ' + flag + sys.exit(1) if not args: usage(0) diff --git a/direct/src/showutil/runp3d.py b/direct/src/showutil/runp3d.py index a439cfafac..bcdbee8c12 100755 --- a/direct/src/showutil/runp3d.py +++ b/direct/src/showutil/runp3d.py @@ -372,20 +372,14 @@ class AppRunner(DirectObject): def notifyRequest(self, message): """ Delivers a notify request to the browser. This is a "this - happened" type notification; it optionally triggers some - JavaScript code execution, and may also trigger some internal - automatic actions. (For instance, the plugin takes down the - splash window when it sees the onwindowopen notification. """ + happened" type notification; it also triggers some JavaScript + code execution, if indicated in the HTML tags, and may also + trigger some internal automatic actions. (For instance, the + plugin takes down the splash window when it sees the + onwindowopen notification. """ self.sendRequest('notify', message) - # Now process any JavaScript that might be waiting for the - # event as well. These are the JavaScript expressions that - # were specified in the HTML embed or object tag. - expression = self.tokenDict.get(message) - if expression: - self.evalScript(expression) - def evalScript(self, expression, needsResponse = False): """ Evaluates an arbitrary JavaScript expression in the global DOM space. This may be deferred if necessary if needsResponse