more download status notifications

This commit is contained in:
David Rose 2009-08-04 01:41:09 +00:00
parent 4bac1d3314
commit e0b1994b61
10 changed files with 186 additions and 83 deletions

View File

@ -83,6 +83,8 @@ P3DInstance(P3D_request_ready_func *func,
// Set some initial properties. // Set some initial properties.
_panda_script_object->set_float_property("downloadProgress", 0.0); _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 // Generate a special notification: onpluginload, indicating the
// plugin has read its parameters and is ready to be queried (even // plugin has read its parameters and is ready to be queried (even
// if Python has not yet started). This notification is special // if Python has not yet started).
// because it generated at the C++ level, here; most of them are send_notify("onpluginload");
// 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);
}
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -321,6 +311,30 @@ get_request() {
P3D_request *request = _baked_requests.front(); P3D_request *request = _baked_requests.front();
_baked_requests.pop_front(); _baked_requests.pop_front();
_request_pending = !_baked_requests.empty(); _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; return request;
} }
@ -720,6 +734,7 @@ make_p3d_request(TiXmlElement *xrequest) {
if (strcmp(rtype, "notify") == 0) { if (strcmp(rtype, "notify") == 0) {
const char *message = xrequest->Attribute("message"); const char *message = xrequest->Attribute("message");
if (message != NULL) { if (message != NULL) {
// A notify message from Python code.
request = new P3D_request; request = new P3D_request;
request->_request_type = P3D_RT_notify; request->_request_type = P3D_RT_notify;
request->_request._notify._message = strdup(message); request->_request._notify._message = strdup(message);
@ -816,6 +831,8 @@ handle_notify_request(const string &message) {
P3D_OBJECT_DECREF(result); P3D_OBJECT_DECREF(result);
} }
_panda_script_object->set_string_property("status", "running");
} else if (message == "onwindowopen") { } else if (message == "onwindowopen") {
// The process told us that it just succesfully opened its // The process told us that it just succesfully opened its
// window. Tear down the splash window. // window. Tear down the splash window.
@ -825,6 +842,8 @@ handle_notify_request(const string &message) {
_splash_window = NULL; _splash_window = NULL;
} }
_panda_script_object->set_string_property("status", "open");
#ifdef __APPLE__ #ifdef __APPLE__
// Start a timer to update the frame repeatedly. This seems to be // Start a timer to update the frame repeatedly. This seems to be
// steadier than waiting for nullEvent. // steadier than waiting for nullEvent.
@ -976,6 +995,17 @@ make_splash_window() {
start_download(download); 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 // Function: P3DInstance::install_progress
// Access: Private // Access: Private
@ -990,6 +1020,40 @@ install_progress(P3DPackage *package, double progress) {
_panda_script_object->set_float_property("downloadProgress", 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 // Function: P3DInstance::paint_window
// Access: Private // Access: Private

View File

@ -107,11 +107,15 @@ private:
const string &property_name, P3D_object *value, const string &property_name, P3D_object *value,
bool needs_response, int unique_id); bool needs_response, int unique_id);
void make_splash_window(); void make_splash_window();
void start_package_download(P3DPackage *package);
void install_progress(P3DPackage *package, double progress); void install_progress(P3DPackage *package, double progress);
void package_ready(P3DPackage *package, bool success);
void paint_window(); void paint_window();
void add_modifier_flags(unsigned int &swb_flags, int modifiers); void add_modifier_flags(unsigned int &swb_flags, int modifiers);
void send_notify(const string &message);
#ifdef __APPLE__ #ifdef __APPLE__
static void timer_callback(CFRunLoopTimerRef timer, void *info); static void timer_callback(CFRunLoopTimerRef timer, void *info);
#endif // __APPLE__ #endif // __APPLE__

View File

@ -235,6 +235,7 @@ start_instance(P3DInstance *inst) {
_panda3d_callback = new PackageCallback(this); _panda3d_callback = new PackageCallback(this);
_panda3d->set_callback(_panda3d_callback); _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 // Function: P3DSession::start_p3dpython
// Access: Private // 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 // Function: P3DSession::PackageCallback::install_progress
// Access: Public, Virtual // Access: Public, Virtual
@ -1126,5 +1130,21 @@ void P3DSession::PackageCallback::
install_progress(P3DPackage *package, double progress) { install_progress(P3DPackage *package, double progress) {
if (this == _session->_panda3d_callback) { if (this == _session->_panda3d_callback) {
_session->install_progress(package, progress); _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";
} }
} }

View File

@ -62,6 +62,7 @@ public:
private: private:
void install_progress(P3DPackage *package, double progress); void install_progress(P3DPackage *package, double progress);
void package_ready(P3DPackage *package, bool success);
void start_p3dpython(); void start_p3dpython();
void spawn_read_thread(); void spawn_read_thread();

View File

@ -34,7 +34,7 @@ P3DToplevelObject::
~P3DToplevelObject() { ~P3DToplevelObject() {
set_pyobj(NULL); set_pyobj(NULL);
// Just in case there are properties we haven't cleared yet. // Clear the local properties.
Properties::const_iterator pi; Properties::const_iterator pi;
for (pi = _properties.begin(); pi != _properties.end(); ++pi) { for (pi = _properties.begin(); pi != _properties.end(); ++pi) {
P3D_object *value = (*pi).second; P3D_object *value = (*pi).second;
@ -139,32 +139,34 @@ get_property(const string &property) {
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
bool P3DToplevelObject:: bool P3DToplevelObject::
set_property(const string &property, P3D_object *value) { set_property(const string &property, P3D_object *value) {
if (_pyobj == NULL) { // First, we set the property locally.
// Without a pyobj, we just store the value locally. if (value != NULL) {
if (value != NULL) { Properties::iterator pi;
Properties::iterator pi; pi = _properties.insert(Properties::value_type(property, NULL)).first;
pi = _properties.insert(Properties::value_type(property, NULL)).first; assert(pi != _properties.end());
assert(pi != _properties.end()); P3D_object *orig_value = (*pi).second;
P3D_object *orig_value = (*pi).second; if (orig_value != value) {
if (orig_value != value) { P3D_OBJECT_XDECREF(orig_value);
P3D_OBJECT_XDECREF(orig_value); (*pi).second = value;
(*pi).second = value; P3D_OBJECT_INCREF(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);
}
} }
} 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; 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); 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; const string &property_name = (*pi).first;
P3D_object *value = (*pi).second; P3D_object *value = (*pi).second;
P3D_OBJECT_SET_PROPERTY(_pyobj, property_name.c_str(), value); P3D_OBJECT_SET_PROPERTY(_pyobj, property_name.c_str(), value);
P3D_OBJECT_DECREF(value);
} }
_properties.clear();
} }
} }
} }

View File

@ -31,7 +31,7 @@ public:
#define LOCK _lock #define LOCK _lock
#define INIT_LOCK(lock) { InitializeCriticalSection(&(lock)._l); (lock)._count = 0; } #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 RELEASE_LOCK(lock) { --((lock)._count); LeaveCriticalSection(&(lock)._l); }
#define DESTROY_LOCK(lock) DeleteCriticalSection(&(lock)._l) #define DESTROY_LOCK(lock) DeleteCriticalSection(&(lock)._l)

View File

@ -70,13 +70,8 @@ PPInstance(NPMIMEType pluginType, NPP instance, uint16 mode,
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
PPInstance:: PPInstance::
~PPInstance() { ~PPInstance() {
#ifdef _WIN32 nout << "Destructing PPInstance\n";
if (_got_window) { cleanup_window();
// Restore the parent window to its own window handler.
HWND hwnd = (HWND)_window.window;
SetWindowLongPtr(hwnd, GWL_WNDPROC, _orig_window_proc);
}
#endif // _WIN32
if (_p3d_inst != NULL) { if (_p3d_inst != NULL) {
P3D_instance_finish(_p3d_inst); P3D_instance_finish(_p3d_inst);
@ -421,6 +416,7 @@ handle_request(P3D_request *request) {
P3D_instance_finish(_p3d_inst); P3D_instance_finish(_p3d_inst);
_p3d_inst = NULL; _p3d_inst = NULL;
} }
cleanup_window();
// Guess the browser doesn't really care. // Guess the browser doesn't really care.
handled = true; handled = true;
break; break;
@ -1074,9 +1070,29 @@ send_window() {
parent_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 // Function: PPInstance::copy_file
// Access: Public // Access: Private
// Description: Copies the data in the file named by from_filename // Description: Copies the data in the file named by from_filename
// into the file named by to_filename. // into the file named by to_filename.
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////

View File

@ -78,6 +78,7 @@ private:
void create_instance(); void create_instance();
void send_window(); void send_window();
void cleanup_window();
bool copy_file(const string &from_filename, const string &to_filename); bool copy_file(const string &from_filename, const string &to_filename);
static void handle_request_loop(); static void handle_request_loop();

View File

@ -78,6 +78,9 @@ for opt, arg in opts:
freezer.handleCustomPath(module) freezer.handleCustomPath(module)
elif opt == '-h': elif opt == '-h':
usage(0) usage(0)
else:
print 'illegal option: ' + flag
sys.exit(1)
if not args: if not args:
usage(0) usage(0)

View File

@ -372,20 +372,14 @@ class AppRunner(DirectObject):
def notifyRequest(self, message): def notifyRequest(self, message):
""" Delivers a notify request to the browser. This is a "this """ Delivers a notify request to the browser. This is a "this
happened" type notification; it optionally triggers some happened" type notification; it also triggers some JavaScript
JavaScript code execution, and may also trigger some internal code execution, if indicated in the HTML tags, and may also
automatic actions. (For instance, the plugin takes down the trigger some internal automatic actions. (For instance, the
splash window when it sees the onwindowopen notification. """ plugin takes down the splash window when it sees the
onwindowopen notification. """
self.sendRequest('notify', message) 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): def evalScript(self, expression, needsResponse = False):
""" Evaluates an arbitrary JavaScript expression in the global """ Evaluates an arbitrary JavaScript expression in the global
DOM space. This may be deferred if necessary if needsResponse DOM space. This may be deferred if necessary if needsResponse