Browse Source

more download status notifications

David Rose 16 years ago
parent
commit
e0b1994b61

+ 78 - 14
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

+ 4 - 0
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__

+ 39 - 19
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
@@ -1093,38 +1121,30 @@ PackageCallback(P3DSession *session) :
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: P3DSession::PackageCallback::package_ready
+//     Function: P3DSession::PackageCallback::install_progress
 //       Access: Public, Virtual
-//  Description: 
+//  Description: This callback is received during the download process
+//               to inform us how much has been installed so far.
 ////////////////////////////////////////////////////////////////////
 void P3DSession::PackageCallback::
-package_ready(P3DPackage *package, bool success) {
+install_progress(P3DPackage *package, double progress) {
   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";
-    }
+    _session->install_progress(package, progress);
   } else {
     nout << "Unexpected callback for P3DSession\n";
   }
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: P3DSession::PackageCallback::install_progress
+//     Function: P3DSession::PackageCallback::package_ready
 //       Access: Public, Virtual
-//  Description: This callback is received during the download process
-//               to inform us how much has been installed so far.
+//  Description: 
 ////////////////////////////////////////////////////////////////////
 void P3DSession::PackageCallback::
-install_progress(P3DPackage *package, double progress) {
+package_ready(P3DPackage *package, bool success) {
   if (this == _session->_panda3d_callback) {
-    _session->install_progress(package, progress);
+    _session->package_ready(package, success);
+  } else {
+    nout << "Unexpected callback for P3DSession\n";
   }
 }

+ 1 - 0
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();

+ 24 - 24
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());
+  // 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;
-      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);
-      }
+      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();
     }
   }
 }

+ 1 - 1
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)
 

+ 24 - 8
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.
 ////////////////////////////////////////////////////////////////////

+ 1 - 0
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();

+ 3 - 0
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)

+ 5 - 11
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