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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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