David Rose 16 years ago
parent
commit
8f96fa71f5

+ 141 - 4
direct/src/plugin/p3dInstance.cxx

@@ -84,6 +84,7 @@ P3DInstance(P3D_request_ready_func *func,
 #endif  // __APPLE__
 
   // Set some initial properties.
+  _panda_script_object->set_float_property("instanceDownloadProgress", 0.0);
   _panda_script_object->set_float_property("downloadProgress", 0.0);
   _panda_script_object->set_string_property("downloadPackageName", "");
   _panda_script_object->set_string_property("downloadPackageDisplayName", "");
@@ -147,6 +148,44 @@ P3DInstance::
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: P3DInstance::set_p3d_url
+//       Access: Public
+//  Description: Specifies a URL that should be contacted to download
+//               the instance data.  Normally this, or
+//               set_p3d_filename(), is only called once.
+//
+//               The instance data at the other end of this URL is
+//               key.  We can't start the instance until we have
+//               downloaded the instance file and examined the
+//               p3d_info.xml, and we know what Python version we need
+//               and so forth.
+////////////////////////////////////////////////////////////////////
+void P3DInstance::
+set_p3d_url(const string &p3d_url) {
+  // Make a temporary file to receive the instance data.
+  char *name = tempnam(NULL, "p3d_");
+  string filename = name;
+  free(name);
+
+  // Mark the time we started downloading, so we'll know when to set
+  // the install label.
+#ifdef _WIN32
+  _start_dl_instance_tick = GetTickCount();
+#else
+  gettimeofday(&_start_dl_instance_timeval, NULL);
+#endif
+  _show_dl_instance_progress = false;
+
+  // Start downloading the data.
+  InstanceDownload *download = new InstanceDownload(this);
+  download->set_url(p3d_url);
+  download->set_filename(filename);
+
+  _panda_script_object->set_string_property("status", "downloading_instance");
+  start_download(download);
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: P3DInstance::set_p3d_filename
 //       Access: Public
@@ -158,6 +197,8 @@ set_p3d_filename(const string &p3d_filename) {
   _got_fparams = true;
   _fparams.set_p3d_filename(p3d_filename);
 
+  _panda_script_object->set_float_property("instanceDownloadProgress", 1.0);
+
   // This also sets up some internal data based on the contents of the
   // above file and the associated tokens.
 
@@ -184,6 +225,9 @@ set_p3d_filename(const string &p3d_filename) {
   // plugin has read its parameters and is ready to be queried (even
   // if Python has not yet started).
   send_notify("onpluginload");
+
+  // Now we're ready to start.
+  inst_mgr->start_instance(this);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -1082,6 +1126,7 @@ make_splash_window() {
   assert(_splash_window == NULL);
 
   _splash_window = new SplashWindowType(this);
+  _splash_window->set_install_label(_install_label);
 
   string splash_image_url = _fparams.lookup_token("splash_img");
   if (!_fparams.has_token("splash_img")) {
@@ -1139,6 +1184,9 @@ report_package_info_ready(P3DPackage *package) {
          << " packages, total " << _total_download_size
          << " bytes required.\n";
 
+    if (_splash_window != NULL) {
+      _splash_window->set_install_progress(0.0);
+    }
     _panda_script_object->set_string_property("status", "downloading");
     send_notify("ondownloadbegin");
 
@@ -1170,9 +1218,7 @@ start_next_download() {
       }
       _panda_script_object->set_string_property("downloadPackageName", package->get_package_name());
       _panda_script_object->set_string_property("downloadPackageDisplayName", name);
-      if (_splash_window != NULL) {
-        _splash_window->set_install_label("Installing " + name);
-      }
+      set_install_label("Installing " + name);
 
       nout << "Downloading " << package->get_package_name()
            << ", package " << _download_package_index + 1
@@ -1204,10 +1250,48 @@ start_next_download() {
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: P3DInstance::report_instance_progress
+//       Access: Private
+//  Description: Notified as the instance file is downloaded.
+////////////////////////////////////////////////////////////////////
+void P3DInstance::
+report_instance_progress(double progress) {
+  if (!_show_dl_instance_progress) {
+    // If we haven't yet set the download label, set it after a full
+    // second has elapsed.  We don't want to set it too soon, because
+    // we're not really sure how long it will take to download (the
+    // instance file might be already in the browser cache).
+#ifdef _WIN32
+    int now = GetTickCount();
+    double elapsed = (double)(now - _start_dl_instance_tick) * 0.001;
+#else
+    struct timeval now;
+    gettimeofday(&now, NULL);
+    double elapsed = (double)(now.tv_sec - _start_dl_instance_timeval.tv_sec) +
+      (double)(now.tv_usec - _start_dl_instance_timeval.tv_usec) / 1000000.0;
+#endif
+
+    // Put up the progress bar after 2 seconds have elapsed, if we've
+    // still got some distance to go; or after 5 seconds have elapsed
+    // regardless.
+    if ((elapsed > 2.0 && progress < 0.7) ||
+        (elapsed > 5.0)) {
+      _show_dl_instance_progress = true;
+    }
+  }
+
+  if (_splash_window != NULL && _show_dl_instance_progress) {
+    _splash_window->set_install_progress(progress);
+  }
+  _panda_script_object->set_float_property("instanceDownloadProgress", progress);
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: P3DInstance::report_package_progress
 //       Access: Private
-//  Description: Notified as a required package is downloaded.
+//  Description: Notified as the packages required by the instance
+//               file are downloaded.
 ////////////////////////////////////////////////////////////////////
 void P3DInstance::
 report_package_progress(P3DPackage *package, double progress) {
@@ -1246,6 +1330,20 @@ report_package_done(P3DPackage *package, bool success) {
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: P3DInstance::set_install_label
+//       Access: Private
+//  Description: Sets the install label that will be displayed on the
+//               splash window, if it is present.
+////////////////////////////////////////////////////////////////////
+void P3DInstance::
+set_install_label(const string &install_label) {
+  _install_label = install_label;
+  if (_splash_window != NULL) {
+    _splash_window->set_install_label(_install_label);
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: P3DInstance::send_notify
 //       Access: Private
@@ -1490,3 +1588,42 @@ download_finished(bool success) {
     }
   }
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DInstance::InstanceDownload::Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+P3DInstance::InstanceDownload::
+InstanceDownload(P3DInstance *inst) :
+  _inst(inst)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DInstance::InstanceDownload::download_progress
+//       Access: Protected, Virtual
+//  Description: Intended to be overloaded to generate an occasional
+//               callback as new data comes in.
+////////////////////////////////////////////////////////////////////
+void P3DInstance::InstanceDownload::
+download_progress() {
+  _inst->report_instance_progress(get_download_progress());
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DInstance::InstanceDownload::download_finished
+//       Access: Protected, Virtual
+//  Description: Intended to be overloaded to generate a callback
+//               when the download finishes, either successfully or
+//               otherwise.  The bool parameter is true if the
+//               download was successful.
+////////////////////////////////////////////////////////////////////
+void P3DInstance::InstanceDownload::
+download_finished(bool success) {
+  P3DFileDownload::download_finished(success);
+  if (success) {
+    // We've successfully downloaded the instance data.
+    _inst->set_p3d_filename(get_filename());
+  }
+}

+ 26 - 2
direct/src/plugin/p3dInstance.h

@@ -27,6 +27,10 @@
 #include <CoreFoundation/CoreFoundation.h>
 #endif
 
+#ifndef _WIN32
+#include <sys/time.h>
+#endif
+
 #include <deque>
 #include <map>
 
@@ -48,6 +52,7 @@ public:
               const P3D_token tokens[], size_t num_tokens, void *user_data);
   ~P3DInstance();
 
+  void set_p3d_url(const string &p3d_url);
   void set_p3d_filename(const string &p3d_filename);
   inline const P3DFileParams &get_fparams() const;
 
@@ -95,10 +100,17 @@ private:
   class SplashDownload : public P3DFileDownload {
   public:
     SplashDownload(P3DInstance *inst);
-
   protected:
     virtual void download_finished(bool success);
-
+  private:
+    P3DInstance *_inst;
+  };
+  class InstanceDownload : public P3DFileDownload {
+  public:
+    InstanceDownload(P3DInstance *inst);
+  protected:
+    virtual void download_progress();
+    virtual void download_finished(bool success);
   private:
     P3DInstance *_inst;
   };
@@ -114,8 +126,10 @@ private:
   void make_splash_window();
   void report_package_info_ready(P3DPackage *package);
   void start_next_download();
+  void report_instance_progress(double progress);
   void report_package_progress(P3DPackage *package, double progress);
   void report_package_done(P3DPackage *package, bool progress);
+  void set_install_label(const string &install_label);
 
   void paint_window();
   void add_modifier_flags(unsigned int &swb_flags, int modifiers);
@@ -158,8 +172,18 @@ private:
 #endif  // __APPLE__
 
   P3DSplashWindow *_splash_window;
+  string _install_label;
   bool _instance_window_opened;
 
+  // Members for deciding whether and when to display the progress bar
+  // for downloading the initial instance data.
+#ifdef _WIN32
+  int _start_dl_instance_tick;
+#else
+  struct timeval _start_dl_instance_timeval;
+#endif
+  bool _show_dl_instance_progress;
+
   typedef vector<P3DPackage *> Packages;
   Packages _packages;
   Packages _downloading_packages;

+ 21 - 7
direct/src/plugin/p3dInstanceManager.cxx

@@ -216,21 +216,35 @@ create_instance(P3D_request_ready_func *func,
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: P3DInstanceManager::start_instance
+//     Function: P3DInstanceManager::set_p3d_filename
 //       Access: Public
-//  Description: Actually starts the instance running.  Before this
-//               call, the instance is in an indeterminate state.  It
-//               is an error to call this more than once for a
-//               particular instance.
+//  Description: Sets the p3d_filename (or p3d_url) on a particular
+//               instance.
 ////////////////////////////////////////////////////////////////////
 bool P3DInstanceManager::
-start_instance(P3DInstance *inst, const string &p3d_filename) {
+set_p3d_filename(P3DInstance *inst, bool is_local,
+                 const string &p3d_filename) {
   if (inst->is_started()) {
     nout << "Instance started twice: " << inst << "\n";
     return false;
   }
-  inst->set_p3d_filename(p3d_filename);
+  if (is_local) {
+    inst->set_p3d_filename(p3d_filename);
+  } else {
+    inst->set_p3d_url(p3d_filename);
+  }
+}
+
 
+////////////////////////////////////////////////////////////////////
+//     Function: P3DInstanceManager::start_instance
+//       Access: Public
+//  Description: Actually starts the instance running on a particular
+//               session.  This is called by the P3DInstance when it
+//               successfully loads its instance file.
+////////////////////////////////////////////////////////////////////
+bool P3DInstanceManager::
+start_instance(P3DInstance *inst) {
   P3DSession *session;
   Sessions::iterator si = _sessions.find(inst->get_session_key());
   if (si == _sessions.end()) {

+ 3 - 1
direct/src/plugin/p3dInstanceManager.h

@@ -57,7 +57,9 @@ public:
                   const P3D_token tokens[], size_t num_tokens, 
                   void *user_data);
 
-  bool start_instance(P3DInstance *inst, const string &p3d_filename);
+  bool set_p3d_filename(P3DInstance *inst, bool is_local,
+                        const string &p3d_filename);
+  bool start_instance(P3DInstance *inst);
   void finish_instance(P3DInstance *inst);
 
   P3DInstance *validate_instance(P3D_instance *instance);

+ 12 - 9
direct/src/plugin/p3dOsxSplashWindow.cxx

@@ -240,15 +240,16 @@ paint_window() {
              &src_rect, &dest_rect, srcCopy, 0);
   }
 
-  if (!_install_label.empty()) {
-    // Draw the progress bar.  We don't draw this bar unless the
-    // install_label has been set nonempty.
-    int bar_width = min((int)(win_width * 0.6), 400);
-    int bar_height = min((int)(win_height * 0.1), 24);
-    int bar_x = (win_width - bar_width) / 2;
-    int bar_y = (win_height - bar_height * 2);
-    
-    int progress = bar_x + 1 + (int)((bar_width - 2) * _install_progress);
+  // Draw the progress bar.  We don't draw this bar at all unless we
+  // have nonzero progress.
+  int bar_width = min((int)(win_width * 0.6), 400);
+  int bar_height = min((int)(win_height * 0.1), 24);
+  int bar_x = (win_width - bar_width) / 2;
+  int bar_y = (win_height - bar_height * 2);
+  
+  int progress_width = (int)((bar_width - 2) * _install_progress);
+  if (progress_width > 0) {
+    int progress = bar_x + 1 + progress_width;
     
     Rect rbar = { bar_y, bar_x, bar_y + bar_height, bar_x + bar_width };
     Rect rneed = { bar_y + 1, progress, bar_y + bar_height - 1, bar_x + bar_width - 1 };
@@ -262,7 +263,9 @@ paint_window() {
     
     RGBColor black = { 0, 0, 0 };
     RGBForeColor(&black);
+  }
 
+  if (!_install_label.empty()) {
     // Now draw the install_label right above it.
     TextFont(0);
     TextFace(bold);

+ 4 - 7
direct/src/plugin/p3dWinSplashWindow.cxx

@@ -34,7 +34,6 @@ P3DWinSplashWindow(P3DInstance *inst) :
   _progress_bar = NULL;
   _text_label = NULL;
   _thread_running = false;
-  _got_install = false;
   _image_filename_changed = false;
   _image_filename_temp = false;
   _install_label_changed = false;
@@ -137,8 +136,6 @@ set_install_label(const string &install_label) {
 ////////////////////////////////////////////////////////////////////
 void P3DWinSplashWindow::
 set_install_progress(double install_progress) {
-  _got_install = true;
-
   ACQUIRE_LOCK(_install_lock);
   _install_progress = install_progress;
   RELEASE_LOCK(_install_lock);
@@ -265,7 +262,6 @@ thread_run() {
     DispatchMessage(&msg);
 
     ACQUIRE_LOCK(_install_lock);
-    bool got_install = _got_install;
     double install_progress = _install_progress;
     if (_image_filename_changed) {
       update_image_filename(_image_filename, _image_filename_temp);
@@ -277,17 +273,18 @@ thread_run() {
     _install_label_changed = false;
     RELEASE_LOCK(_install_lock);
 
-    if (got_install && install_progress != last_progress) {
+    if (install_progress != last_progress) {
+      int progress = (int)(install_progress * 100.0);
       if (_progress_bar == NULL) {
         // Is it time to create the progress bar?
-        if (!_install_label.empty()) {
+        if (progress != 0) {
           make_progress_bar();
         }
       } else {
         // Update the progress bar.  We do this only within the
         // thread, to ensure we don't get a race condition when
         // starting or closing the thread.
-        SendMessage(_progress_bar, PBM_SETPOS, (int)(install_progress * 100.0), 0);
+        SendMessage(_progress_bar, PBM_SETPOS, progress, 0);
         
         last_progress = install_progress;
       }

+ 5 - 11
direct/src/plugin/p3dX11SplashWindow.cxx

@@ -57,7 +57,6 @@ P3DX11SplashWindow(P3DInstance *inst) :
   _resized_width = 0;
   _resized_height = 0;
   _graphics_context = None;
-  _got_install = false;
   _image_filename_changed = false;
   _image_filename_temp = false;
   _install_label_changed = false;
@@ -366,19 +365,17 @@ subprocess_run() {
     _image_filename_changed = false;
 
     if (override || have_event || install_label != prev_label) {
-      redraw(install_label);
       override = false;
-
-      // Don't draw the progress bar unless we have some text in
-      // install_label.
-      if (!install_label.empty()) {
+      
+      if (install_progress != 0.0) {
+        redraw(install_label);
         XFillRectangle(_display, _window, _graphics_context, 12, _height - 18,
                        (unsigned int)(install_progress * (_width - 24)), 7);
       }
       XFlush(_display);
 
     } else if (install_progress != prev_progress) {
-      if (!install_label.empty()) {
+      if (install_progress != 0.0) {
         XFillRectangle(_display, _window, _graphics_context, 12, _height - 18,
                        (unsigned int)(install_progress * (_width - 24)), 7);
       }
@@ -457,7 +454,6 @@ receive_command() {
         double install_progress = 0.0;
         xcommand->Attribute("install_progress", &install_progress);
 
-        _got_install = true;
         _install_progress = install_progress;
       }
     }
@@ -513,7 +509,7 @@ redraw(string label) {
     XClearArea(_display, _window, 10, _height - 20, _width - 20, 10, false);
   }
 
-  if (!label.empty()) {
+  if (_install_progress != 0.0) {
     // Draw the rest - the label and the progress bar outline.
     int text_width = label.size() * 6;
     int text_height = 10;
@@ -587,8 +583,6 @@ setup_gc() {
     return;
   }
 
-  string install_label = _install_label;
-  double install_progress = _install_progress;
   _install_label_changed = false;
   
   XFontStruct* fs = XLoadQueryFont(_display, "6x13");

+ 0 - 1
direct/src/plugin/p3dX11SplashWindow.h

@@ -70,7 +70,6 @@ private:
   int _width, _height;
   
   bool _own_display;
-  bool _got_install;
   bool _image_filename_changed;
   string _image_filename;
   bool _image_filename_temp;

+ 6 - 2
direct/src/plugin/p3d_plugin.cxx

@@ -116,7 +116,8 @@ P3D_new_instance(P3D_request_ready_func *func,
 }
 
 bool
-P3D_instance_start(P3D_instance *instance, const char *p3d_filename) {
+P3D_instance_start(P3D_instance *instance, bool is_local, 
+                   const char *p3d_filename) {
   nout << "instance_start\n";
   assert(P3DInstanceManager::get_global_ptr()->is_initialized());
   if (p3d_filename == NULL) {
@@ -127,7 +128,10 @@ P3D_instance_start(P3D_instance *instance, const char *p3d_filename) {
   P3DInstance *inst = inst_mgr->validate_instance(instance);
   bool result = false;
   if (inst != NULL) {
-    result = inst_mgr->start_instance(inst, p3d_filename);
+    // We don't actually start it immediately; the instance will have
+    // to download the p3d url and read it, reading the python
+    // version, before it can start.
+    result = inst_mgr->set_p3d_filename(inst, is_local, p3d_filename);
   }
   RELEASE_LOCK(_api_lock);
   return result;

+ 6 - 6
direct/src/plugin/p3d_plugin.h

@@ -79,7 +79,7 @@ extern "C" {
    (below). This number will be incremented whenever there are changes
    to any of the interface specifications defined in this header
    file. */
-#define P3D_API_VERSION 6
+#define P3D_API_VERSION 7
 
 /************************ GLOBAL FUNCTIONS **************************/
 
@@ -240,14 +240,14 @@ P3D_new_instance_func(P3D_request_ready_func *func,
    P3D_new_instance(); it actually starts the instance running.
    Before this call, the instance will be in an indeterminate state.
 
-   For p3d_filename pass the name of a file on disk that contains the
-   contents of the p3d file that should be launched within the
-   instance.  If this is empty or NULL, the "src" token (below) will
-   be downloaded instead.
+   If is_local is true, then p3d_filename contains the name of a local
+   p3d file on disk.  If false, then p3d_filename contains a URL that
+   should be downloaded to retrieve the p3d file.
 
    The return value is true on success, false on failure. */
 typedef bool
-P3D_instance_start_func(P3D_instance *instance, const char *p3d_filename);
+P3D_instance_start_func(P3D_instance *instance, bool is_local,
+                        const char *p3d_filename);
 
 
 /* Call this function to interrupt a particular instance and stop it

+ 0 - 1
direct/src/plugin_npapi/ppDownloadRequest.h

@@ -28,7 +28,6 @@ public:
   enum RequestType {
     RT_contents_file,
     RT_core_dll,
-    RT_instance_data,
     RT_user
   };
 

+ 14 - 22
direct/src/plugin_npapi/ppInstance.cxx

@@ -61,8 +61,7 @@ PPInstance(NPMIMEType pluginType, NPP instance, uint16 mode,
 
   _root_dir = find_root_dir();
 
-  _started_instance_data = false;
-  _got_instance_data = false;
+  _got_instance_url = false;
   _got_window = false;
   _python_window_open = false;
 }
@@ -180,15 +179,18 @@ new_stream(NPMIMEType type, NPStream *stream, bool seekable, uint16 *stype) {
     // This is an unsolicited stream.  Assume the first unsolicited
     // stream we receive is the instance data; any other unsolicited
     // stream is an error.
-    if (!_started_instance_data) {
-      stream->notifyData = new PPDownloadRequest(PPDownloadRequest::RT_instance_data);
-      *stype = NP_ASFILEONLY;
-      _started_instance_data = true;
-      return NPERR_NO_ERROR;
+
+    // We don't let Mozilla finish downloading the instance data, but
+    // we do extract its URL to pass to the instance.
+    if (!_got_instance_url && stream->url != NULL) {
+      _got_instance_url = true;
+      _instance_url = stream->url;
+      if (_p3d_inst != NULL) {
+        P3D_instance_start(_p3d_inst, false, _instance_url.c_str());
+      }
     }
 
-    // This is an unexpected unsolicited stream.  (Firefox seems to
-    // give us the instance data twice for some reason.)
+    // Don't finish downloading the unsolicited stream.
     return NPERR_GENERIC_ERROR;
   }
 
@@ -793,17 +795,6 @@ downloaded_file(PPDownloadRequest *req, const string &filename) {
     downloaded_plugin(filename);
     break;
 
-  case PPDownloadRequest::RT_instance_data:
-    // This is the instance data, e.g. the p3d filename.  Now we can
-    // launch the instance.
-    _got_instance_data = true;
-    _p3d_filename = filename;
-
-    if (_p3d_inst != NULL) {
-      P3D_instance_start(_p3d_inst, _p3d_filename.c_str());
-    }
-    break;
-
   case PPDownloadRequest::RT_user:
     // Normally, RT_user requests won't come here, unless we
     // short-circuited the browser by "downloading" a file:// url.  In
@@ -987,8 +978,8 @@ create_instance() {
       _script_object->set_p3d_object(obj);
     }
 
-    if (_got_instance_data) {
-      P3D_instance_start(_p3d_inst, _p3d_filename.c_str());
+    if (_got_instance_url) {
+      P3D_instance_start(_p3d_inst, false, _instance_url.c_str());
     }
 
     if (_got_window) {
@@ -1314,6 +1305,7 @@ is_done() const {
 void PPInstance::StreamingFileData::
 thread_run() {
   static const size_t buffer_size = 81920;
+  //static const size_t buffer_size = 512;
   char buffer[buffer_size];
 
   _file.read(buffer, buffer_size);

+ 2 - 3
direct/src/plugin_npapi/ppInstance.h

@@ -98,9 +98,8 @@ private:
   string _root_dir;
   FileSpec _core_api_dll;
 
-  bool _started_instance_data;
-  bool _got_instance_data;
-  string _p3d_filename;
+  bool _got_instance_url;
+  string _instance_url;
 
   // This class is used for feeding local files (accessed via a
   // "file://" url) into the core API.

+ 1 - 1
direct/src/plugin_standalone/panda3d.cxx

@@ -632,7 +632,7 @@ create_instance(const string &arg, P3D_window_type window_type,
   if (inst != NULL) {
     P3D_instance_setup_window
       (inst, window_type, win_x, win_y, win_width, win_height, parent_window);
-    P3D_instance_start(inst, os_p3d_filename.c_str());
+    P3D_instance_start(inst, true, os_p3d_filename.c_str());
   }
 
   return inst;