Browse Source

visible install progress indicator

David Rose 16 years ago
parent
commit
84dff5ad19

+ 7 - 3
direct/src/plugin/Sources.pp

@@ -20,7 +20,9 @@
     p3dInstanceManager.h p3dInstanceManager.I \
     p3dMultifileReader.h p3dMultifileReader.I \
     p3dPackage.h p3dPackage.I \
-    p3dSession.h p3dSession.I
+    p3dProgressWindow.h p3dProgressWindow.I \
+    p3dSession.h p3dSession.I \
+    p3dWinProgressWindow.h p3dWinProgressWindow.I
 
   #define INCLUDED_SOURCES \
     p3d_plugin.cxx \
@@ -30,12 +32,14 @@
     p3dInstanceManager.cxx \
     p3dMultifileReader.cxx \
     p3dPackage.cxx \
-    p3dSession.cxx
+    p3dProgressWindow.cxx \
+    p3dSession.cxx \
+    p3dWinProgressWindow.cxx
 
   #define INSTALL_HEADERS \
     p3d_plugin.h
 
-  #define WIN_SYS_LIBS shell32.lib
+  #define WIN_SYS_LIBS user32.lib gdi32.lib shell32.lib comctl32.lib
 
 #end lib_target
 

+ 1 - 1
direct/src/plugin/p3dDownload.cxx

@@ -128,7 +128,7 @@ receive_data(const unsigned char *this_data, size_t this_data_size) {
 void P3DDownload::
 download_progress() {
   time_t now = time(NULL);
-  if (now != _last_reported_time) {
+  if (now != _last_reported_time || true) {
     cerr << "Downloading " << get_url() << ": " 
          << int(get_download_progress() * 1000.0) / 10.0 << "\n";
     _last_reported_time = now;

+ 66 - 0
direct/src/plugin/p3dInstance.I

@@ -24,6 +24,72 @@ get_p3d_filename() const {
   return _p3d_filename;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: P3DInstance::get_window_type
+//       Access: Public
+//  Description: Returns the window_type that was passed to the
+//               constructor.
+////////////////////////////////////////////////////////////////////
+inline P3D_window_type P3DInstance::
+get_window_type() const {
+  return _window_type;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DInstance::get_window_x
+//       Access: Public
+//  Description: Returns the window origin X coordinate that was
+//               passed to the constructor.
+////////////////////////////////////////////////////////////////////
+inline int P3DInstance::
+get_win_x() const {
+  return _win_x;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DInstance::get_win_y
+//       Access: Public
+//  Description: Returns the window origin Y coordinate that was
+//               passed to the constructor.
+////////////////////////////////////////////////////////////////////
+inline int P3DInstance::
+get_win_y() const {
+  return _win_y;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DInstance::get_win_width
+//       Access: Public
+//  Description: Returns the window width that was passed to the
+//               constructor.
+////////////////////////////////////////////////////////////////////
+inline int P3DInstance::
+get_win_width() const {
+  return _win_width;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DInstance::get_win_height
+//       Access: Public
+//  Description: Returns the window height that was passed to the
+//               constructor.
+////////////////////////////////////////////////////////////////////
+inline int P3DInstance::
+get_win_height() const {
+  return _win_height;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DInstance::get_parent_window
+//       Access: Public
+//  Description: Returns the parent window handle that was passed to
+//               the constructor.
+////////////////////////////////////////////////////////////////////
+inline P3D_window_handle P3DInstance::
+get_parent_window() const {
+  return _parent_window;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: P3DInstance::get_instance_id
 //       Access: Public

+ 20 - 0
direct/src/plugin/p3dInstance.cxx

@@ -41,6 +41,7 @@ P3DInstance(P3D_request_ready_func *func,
   _parent_window(parent_window)
 {
   fill_tokens(tokens, num_tokens);
+  cerr << "instance, size = " << _win_width << " " << _win_height << "\n";
 
   _instance_id = _next_instance_id;
   ++_next_instance_id;
@@ -56,6 +57,7 @@ P3DInstance(P3D_request_ready_func *func,
   _python_version = "python24";
 
   _session = NULL;
+  _requested_stop = false;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -271,6 +273,24 @@ start_download(P3DDownload *download) {
   add_request(request);
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: P3DInstance::request_stop
+//       Access: Public
+//  Description: Asks the host to shut down this particular instance,
+//               presumably because the user has indicated it should
+//               exit.
+////////////////////////////////////////////////////////////////////
+void P3DInstance::
+request_stop() {
+  if (!_requested_stop) {
+    _requested_stop = true;
+    P3D_request *request = new P3D_request;
+    request->_instance = this;
+    request->_request_type = P3D_RT_stop;
+    add_request(request);
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: P3DInstance::make_xml
 //       Access: Public

+ 9 - 0
direct/src/plugin/p3dInstance.h

@@ -58,12 +58,20 @@ public:
                        size_t this_data_size);
 
   inline const string &get_p3d_filename() const;
+  inline P3D_window_type get_window_type() const;
+  inline int get_win_x() const;
+  inline int get_win_y() const;
+  inline int get_win_width() const;
+  inline int get_win_height() const;
+  inline P3D_window_handle get_parent_window() const;
+
   inline int get_instance_id() const;
   inline const string &get_session_key() const;
   inline const string &get_python_version() const;
   string lookup_token(const string &keyword) const;
 
   void start_download(P3DDownload *download);
+  void request_stop();
 
   TiXmlElement *make_xml();
 
@@ -96,6 +104,7 @@ private:
   LOCK _request_lock;
   typedef deque<P3D_request *> Requests;
   Requests _pending_requests;
+  bool _requested_stop;
 
   static int _next_instance_id;
 

+ 11 - 2
direct/src/plugin/p3dInstanceManager.cxx

@@ -45,6 +45,15 @@ P3DInstanceManager() {
   pthread_cond_init(&_request_ready_cvar, NULL);
 #endif
 
+#ifdef _WIN32
+  // Ensure the appropriate Windows common controls are available to
+  // this application.
+  INITCOMMONCONTROLSEX icc;
+  icc.dwSize = sizeof(icc);
+  icc.dwICC = ICC_PROGRESS_CLASS;
+  InitCommonControlsEx(&icc);
+#endif
+
   _command_instance = NULL;
 }
 
@@ -235,14 +244,14 @@ wait_request() {
 //               package.
 ////////////////////////////////////////////////////////////////////
 P3DPackage *P3DInstanceManager::
-get_package(const string &package_name, const string &package_version) {
+get_package(const string &package_name, const string &package_version, const string &package_output_name) {
   string key = package_name + "_" + package_version;
   Packages::iterator pi = _packages.find(key);
   if (pi != _packages.end()) {
     return (*pi).second;
   }
 
-  P3DPackage *package = new P3DPackage(package_name, package_version);
+  P3DPackage *package = new P3DPackage(package_name, package_version, package_output_name);
   bool inserted = _packages.insert(Packages::value_type(key, package)).second;
   assert(inserted);
 

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

@@ -58,7 +58,8 @@ public:
   void wait_request();
 
   P3DPackage *get_package(const string &package_name, 
-                          const string &package_version);
+                          const string &package_version,
+                          const string &package_output_name);
 
   inline P3DInstance *get_command_instance() const;
   inline int get_num_instances() const;

+ 39 - 3
direct/src/plugin/p3dMultifileReader.cxx

@@ -14,6 +14,21 @@
 
 #include "p3dMultifileReader.h"
 #include "p3dInstanceManager.h"
+#include "p3dPackage.h"
+
+#include <time.h>
+
+#ifdef _WIN32
+#include <sys/utime.h>
+#include <direct.h>
+#define stat _stat
+#define utime _utime
+#define utimbuf _utimbuf
+
+#else
+#include <utime.h>
+
+#endif
 
 // This sequence of bytes begins each Multifile to identify it as a
 // Multifile.
@@ -38,9 +53,15 @@ P3DMultifileReader() {
 //  Description: Reads the named multifile, and extracts all files
 //               within it to the indicated directory.  Returns true
 //               on success, false on failure.
+//
+//               The parameters package, start_progress, and
+//               progress_size are provided to make the appropriate
+//               status updates on the package's progress callbacks
+//               during this operation.
 ////////////////////////////////////////////////////////////////////
 bool P3DMultifileReader::
-extract(const string &pathname, const string &to_dir) {
+extract(const string &pathname, const string &to_dir,
+        P3DPackage *package, double start_progress, double progress_size) {
   _subfiles.clear();
 
   _in.open(pathname.c_str(), ios::in | ios::binary);
@@ -70,7 +91,7 @@ extract(const string &pathname, const string &to_dir) {
     return false;
   }
 
-  // We don't care about the timestamp.
+  // We don't care about the overall timestamp.
   read_uint32();
 
   if (!read_index()) {
@@ -81,6 +102,7 @@ extract(const string &pathname, const string &to_dir) {
   P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
 
   // Now walk through all of the files.
+  size_t num_processed = 0;
   Subfiles::iterator si;
   for (si = _subfiles.begin(); si != _subfiles.end(); ++si) {
     const Subfile &s = (*si);
@@ -117,6 +139,20 @@ extract(const string &pathname, const string &to_dir) {
       cerr << "Unable to extract " << s._filename << "\n";
       return false;
     }
+
+    // Set the timestamp according to the multifile.
+    out.close();
+    utimbuf utb;
+    utb.actime = time(NULL);
+    utb.modtime = s._timestamp;
+    utime(output_pathname.c_str(), &utb);
+
+
+    ++num_processed;
+    if (package != NULL) {
+      double progress = (double)num_processed / (double)_subfiles.size();
+      package->report_progress(start_progress + progress * progress_size);
+    }
   }
 
   return true;
@@ -144,7 +180,7 @@ read_index() {
       cerr << "Unsupported per-subfile options in multifile\n";
       return false;
     }
-    read_uint32();
+    s._timestamp = read_uint32();
     size_t name_length = read_uint16();
     char *buffer = new char[name_length];
     _in.read(buffer, name_length);

+ 6 - 1
direct/src/plugin/p3dMultifileReader.h

@@ -17,6 +17,8 @@
 
 #include "p3d_plugin_common.h"
 
+class P3DPackage;
+
 ////////////////////////////////////////////////////////////////////
 //       Class : P3DMultifileReader
 // Description : A way-simple implementation of Panda's multifile
@@ -29,7 +31,9 @@ class P3DMultifileReader {
 public:
   P3DMultifileReader();
 
-  bool extract(const string &pathname, const string &to_dir);
+  bool extract(const string &pathname, const string &to_dir,
+               P3DPackage *package, double start_progress, 
+               double progress_size);
 
 private:
   bool read_index();
@@ -43,6 +47,7 @@ private:
     string _filename;
     size_t _start;
     size_t _length;
+    size_t _timestamp;
   };
 
   typedef vector<Subfile> Subfiles;

+ 18 - 1
direct/src/plugin/p3dPackage.I

@@ -50,7 +50,11 @@ get_package_dir() const {
 ////////////////////////////////////////////////////////////////////
 //     Function: P3DPackage::get_package_name
 //       Access: Public
-//  Description: Returns the name of this package.
+//  Description: Returns the name of this package.  This is an
+//               internal name, used to generate filenames and the
+//               like; it will generally be all-lowercase and will not
+//               contain spaces.  See also get_package_output_name()
+//               for a name suitable for displaying to the user.
 ////////////////////////////////////////////////////////////////////
 inline const string &P3DPackage::
 get_package_name() const {
@@ -67,6 +71,19 @@ get_package_version() const {
   return _package_version;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: P3DPackage::get_package_output_name
+//       Access: Public
+//  Description: Returns the name of this package, for output to the
+//               user.  This will be the "public" name of the package,
+//               as formatted for user consumption; it will include
+//               capital letters and spaces where appropriate.
+////////////////////////////////////////////////////////////////////
+inline const string &P3DPackage::
+get_package_output_name() const {
+  return _package_output_name;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: P3DPackage::decode_hexdigit
 //       Access: Private

+ 82 - 4
direct/src/plugin/p3dPackage.cxx

@@ -38,15 +38,23 @@
 
 #endif
 
+// The relative breakdown of the full install process.  Each phase is
+// worth this fraction of the total movement of the progress bar.
+static const double download_portion = 0.9;
+static const double uncompress_portion = 0.05;
+static const double extract_portion = 0.05;
+
 ////////////////////////////////////////////////////////////////////
 //     Function: P3DPackage::Constructor
 //       Access: Public
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 P3DPackage::
-P3DPackage(const string &package_name, const string &package_version) :
+P3DPackage(const string &package_name, const string &package_version,
+           const string &package_output_name) :
   _package_name(package_name),
-  _package_version(package_version)
+  _package_version(package_version),
+  _package_output_name(package_output_name)
 {
   _package_fullname = _package_name + "_" + _package_version;
   _ready = false;
@@ -262,6 +270,16 @@ download_compressed_archive(bool allow_partial) {
   start_download(DT_compressed_archive, url, target_pathname, allow_partial);
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: P3DPackage::compressed_archive_download_progress
+//       Access: Private
+//  Description: Called as the file is downloaded.
+////////////////////////////////////////////////////////////////////
+void P3DPackage::
+compressed_archive_download_progress(double progress) {
+  report_progress(download_portion * progress);
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: P3DPackage::compressed_archive_download_finished
 //       Access: Private
@@ -356,6 +374,7 @@ uncompress_archive() {
     return;
   }
 
+  size_t total_out = 0;
   while (true) {
     if (z.avail_in == 0 && !eof) {
       source.read(decompress_buffer, decompress_buffer_size);
@@ -376,6 +395,12 @@ uncompress_archive() {
         report_done(false);
         return;
       }
+      total_out += (write_buffer_size - z.avail_out);
+      if (_uncompressed_archive._size != 0) {
+        double progress = (double)total_out / (double)_uncompressed_archive._size;
+        progress = min(progress, 1.0);
+        report_progress(download_portion + uncompress_portion * progress);
+      }
     }
 
     if (result == Z_STREAM_END) {
@@ -430,7 +455,8 @@ extract_archive() {
 
   string source_pathname = _package_dir + "/" + _uncompressed_archive._filename;
   P3DMultifileReader reader;
-  if (!reader.extract(source_pathname, _package_dir)) {
+  if (!reader.extract(source_pathname, _package_dir,
+                      this, download_portion + uncompress_portion, extract_portion)) {
     cerr << "Failure extracting " << _uncompressed_archive._filename
          << "\n";
     report_done(false);
@@ -441,6 +467,20 @@ extract_archive() {
   report_done(true);
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: P3DPackage::report_progress
+//       Access: Private
+//  Description: Reports the indicated install progress to all
+//               listening callbacks.
+////////////////////////////////////////////////////////////////////
+void P3DPackage::
+report_progress(double progress) {
+  Callbacks::iterator ci;
+  for (ci = _callbacks.begin(); ci != _callbacks.end(); ++ci) {
+    (*ci)->install_progress(this, progress);
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: P3DPackage::report_done
 //       Access: Private
@@ -558,9 +598,27 @@ stream_hex(ostream &out, const unsigned char *source, size_t size) {
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: P3DPackage::Callback::Destructor
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+P3DPackage::Callback::
+~Callback() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DPackage::Callback::install_progress
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void P3DPackage::Callback::
+install_progress(P3DPackage *package, double progress) {
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: P3DPackage::Callback::package_ready
-//       Access: Public
+//       Access: Public, Virtual
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 void P3DPackage::Callback::
@@ -579,6 +637,26 @@ Download(P3DPackage *package, DownloadType dtype) :
 {
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: P3DPackage::Download::download_progress
+//       Access: Protected, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void P3DPackage::Download::
+download_progress() {
+  P3DFileDownload::download_progress();
+  assert(_package->_active_download == this);
+
+  switch (_dtype) {
+  case DT_desc_file:
+    break;
+
+  case DT_compressed_archive:
+    _package->compressed_archive_download_progress(get_download_progress());
+    break;
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: P3DPackage::Download::download_finished
 //       Access: Protected, Virtual

+ 10 - 1
direct/src/plugin/p3dPackage.h

@@ -32,11 +32,14 @@
 ////////////////////////////////////////////////////////////////////
 class P3DPackage {
 public:
-  P3DPackage(const string &package_name, const string &package_version);
+  P3DPackage(const string &package_name, const string &package_version,
+             const string &package_output_name);
   ~P3DPackage();
 
   class Callback {
   public:
+    virtual ~Callback();
+    virtual void install_progress(P3DPackage *package, double progress);
     virtual void package_ready(P3DPackage *package, bool success);
   };
 
@@ -45,6 +48,7 @@ public:
   inline const string &get_package_dir() const;
   inline const string &get_package_name() const;
   inline const string &get_package_version() const;
+  inline const string &get_package_output_name() const;
 
   void set_callback(Callback *callback);
   void cancel_callback(Callback *callback);
@@ -60,6 +64,7 @@ private:
     Download(P3DPackage *package, DownloadType dtype);
 
   protected:
+    virtual void download_progress();
     virtual void download_finished(bool success);
 
   private:
@@ -72,11 +77,13 @@ private:
   void got_desc_file(TiXmlDocument *doc, bool freshly_downloaded);
 
   void download_compressed_archive(bool allow_partial);
+  void compressed_archive_download_progress(double progress);
   void compressed_archive_download_finished(bool success);
 
   void uncompress_archive();
   void extract_archive();
 
+  void report_progress(double progress);
   void report_done(bool success);
   void start_download(DownloadType dtype, const string &url, 
                       const string &pathname, bool allow_partial);
@@ -91,6 +98,7 @@ private:
 private:
   string _package_name;
   string _package_version;
+  string _package_output_name;
   string _package_fullname;
   string _package_dir;
 
@@ -131,6 +139,7 @@ private:
   Components _components;
 
   friend class Download;
+  friend class P3DMultifileReader;
 };
 
 #include "p3dPackage.I"

+ 14 - 0
direct/src/plugin/p3dProgressWindow.I

@@ -0,0 +1,14 @@
+// Filename: p3dProgressWindow.I
+// Created by:  drose (17Jun09)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+

+ 60 - 0
direct/src/plugin/p3dProgressWindow.cxx

@@ -0,0 +1,60 @@
+// Filename: p3dProgressWindow.cxx
+// Created by:  drose (17Jun09)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#include "p3dProgressWindow.h"
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DProgressWindow::Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+P3DProgressWindow::
+P3DProgressWindow(P3DPackage *package, P3DSession *session, 
+                  P3DInstance *inst) : 
+  _package(package),
+  _session(session),
+  _inst(inst)
+{
+  _window_type = inst->get_window_type();
+  _win_x = inst->get_win_x();
+  _win_y = inst->get_win_y();
+  _win_width = inst->get_win_width();
+  _win_height = inst->get_win_height();
+  _parent_window = inst->get_parent_window();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DProgressWindow::package_ready
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void P3DProgressWindow::
+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 {
+        cerr << "Failed to install " << package->get_package_name()
+             << "_" << package->get_package_version() << "\n";
+      }
+    } else {
+      cerr << "Unexpected panda3d package: " << package << "\n";
+    }
+  } else {
+    cerr << "Unexpected callback for P3DSession\n";
+  }
+}
+

+ 53 - 0
direct/src/plugin/p3dProgressWindow.h

@@ -0,0 +1,53 @@
+// Filename: p3dProgressWindow.h
+// Created by:  drose (17Jun09)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+
+#ifndef P3DPROGRESSWINDOW_H
+#define P3DPROGRESSWINDOW_H
+
+#include "p3d_plugin_common.h"
+#include "p3dPackage.h"
+
+class P3DInstance;
+
+////////////////////////////////////////////////////////////////////
+//       Class : P3DProgressWindow
+// Description : This window is displayed temporarily, in place of an
+//               instance's actual window, during the initial download
+//               of the Panda3D code.  When the download is finished,
+//               it notifies the session.
+//
+//               This is the base implementation; it contains no
+//               specific code to open a window.
+////////////////////////////////////////////////////////////////////
+class P3DProgressWindow : public P3DPackage::Callback {
+public:
+  P3DProgressWindow(P3DPackage *package, P3DSession *session, P3DInstance *inst);
+
+  virtual void package_ready(P3DPackage *package, bool success);
+  
+protected:
+  P3DPackage *_package;
+  P3DSession *_session;
+  P3DInstance *_inst;
+
+  P3D_window_type _window_type;
+  int _win_x, _win_y;
+  int _win_width, _win_height;
+  P3D_window_handle _parent_window;
+};
+
+#include "p3dProgressWindow.I"
+
+#endif

+ 23 - 41
direct/src/plugin/p3dSession.cxx

@@ -15,11 +15,19 @@
 #include "p3dSession.h"
 #include "p3dInstance.h"
 #include "p3dInstanceManager.h"
+#include "p3dProgressWindow.h"
+#include "p3dWinProgressWindow.h"
 
 #ifndef _WIN32
 #include <fcntl.h>
 #endif
 
+#ifdef _WIN32
+typedef P3DWinProgressWindow ProgressWinType;
+#else
+typedef P3DProgressWindow ProgressWinType;
+#endif
+
 ////////////////////////////////////////////////////////////////////
 //     Function: P3DSession::Constructor
 //       Access: Public
@@ -42,7 +50,7 @@ P3DSession(P3DInstance *inst) {
 
   P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
 
-  _panda3d = inst_mgr->get_package("panda3d", "dev");
+  _panda3d = inst_mgr->get_package("panda3d", "dev", "Panda3D");
   _panda3d_callback = NULL;
   _python_root_dir = _panda3d->get_package_dir();
 
@@ -147,7 +155,19 @@ start_instance(P3DInstance *inst) {
   } else {
     // Otherwise, set a callback, so we'll know when it is ready.
     if (_panda3d_callback == NULL) {
-      _panda3d_callback = new PackageCallback(this);
+
+      // The callback object will be a ProgressWindow, to show
+      // visual progress to the user while we're downloading.
+      if (inst->get_window_type() == P3D_WT_hidden) {
+        // For a hidden window, just create an instance of the base
+        // class, which manifests no actual window.
+        _panda3d_callback = new P3DProgressWindow(_panda3d, this, inst);
+      } else {
+        // For a non-hidden window, create an instance of
+        // ProgressWinType, which is typedeffed above to be the kind
+        // of class that actually does manifest a window.
+        _panda3d_callback = new ProgressWinType(_panda3d, this, inst);
+      }
       _panda3d->set_callback(_panda3d_callback);
     }
   }
@@ -401,10 +421,7 @@ rt_terminate() {
 
   for (Instances::iterator ii = icopy.begin(); ii != icopy.end(); ++ii) {
     P3DInstance *inst = (*ii).second;
-    P3D_request *request = new P3D_request;
-    request->_instance = inst;
-    request->_request_type = P3D_RT_stop;
-    inst->add_request(request);
+    inst->request_stop();
   }
 }
 
@@ -633,38 +650,3 @@ posix_create_process(const string &program, const string &start_dir,
 }
 #endif  // _WIN32
 
-
-////////////////////////////////////////////////////////////////////
-//     Function: P3DSession::PackageCallback::Constructor
-//       Access: Public
-//  Description: 
-////////////////////////////////////////////////////////////////////
-P3DSession::PackageCallback::
-PackageCallback(P3DSession *session) : _session(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 {
-        cerr << "Failed to install " << package->get_package_name()
-             << "_" << package->get_package_version() << "\n";
-      }
-    } else {
-      cerr << "Unexpected panda3d package: " << package << "\n";
-    }
-  } else {
-    cerr << "Unexpected callback for P3DSession\n";
-  }
-}
-

+ 3 - 11
direct/src/plugin/p3dSession.h

@@ -24,6 +24,7 @@
 #include <tinyxml.h>
 
 class P3DInstance;
+class P3DProgressWindow;
 
 ////////////////////////////////////////////////////////////////////
 //       Class : P3DSession
@@ -92,17 +93,8 @@ private:
   typedef vector<TiXmlDocument *> Commands;
   Commands _commands;
 
-  class PackageCallback : public P3DPackage::Callback {
-  public:
-    PackageCallback(P3DSession *session);
-    virtual void package_ready(P3DPackage *package, bool success);
-    
-  private:
-    P3DSession *_session;
-  };
-
   P3DPackage *_panda3d;
-  PackageCallback *_panda3d_callback;
+  P3DProgressWindow *_panda3d_callback;
 
   // Members for communicating with the p3dpython child process.
 #ifdef _WIN32
@@ -124,7 +116,7 @@ private:
   pthread_t _read_thread;
 #endif
 
-  friend class PackageCallback;
+  friend class P3DProgressWindow;
 };
 
 #include "p3dSession.I"

+ 14 - 0
direct/src/plugin/p3dWinProgressWindow.I

@@ -0,0 +1,14 @@
+// Filename: p3dWinProgressWindow.I
+// Created by:  drose (17Jun09)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+

+ 354 - 0
direct/src/plugin/p3dWinProgressWindow.cxx

@@ -0,0 +1,354 @@
+// Filename: p3dWinProgressWindow.cxx
+// Created by:  drose (17Jun09)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#include "p3dWinProgressWindow.h"
+
+#ifdef _WIN32
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DWinProgressWindow::Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+P3DWinProgressWindow::
+P3DWinProgressWindow(P3DPackage *package, P3DSession *session,
+                     P3DInstance *inst) : 
+  P3DProgressWindow(package, session, inst)
+{
+  _thread = NULL;
+  _hwnd = NULL;
+  _progress_bar = NULL;
+  _thread_running = false;
+
+  INIT_LOCK(_progress_lock);
+
+  assert(_window_type != P3D_WT_hidden);
+  start_thread();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DWinProgressWindow::Destructor
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+P3DWinProgressWindow::
+~P3DWinProgressWindow() {
+  stop_thread();
+
+  DESTROY_LOCK(_progress_lock);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DWinProgressWindow::install_progress
+//       Access: Public, Virtual
+//  Description: This callback is received during the download process
+//               to inform us how much has been installed so far.
+////////////////////////////////////////////////////////////////////
+void P3DWinProgressWindow::
+install_progress(P3DPackage *package, double progress) {
+  P3DProgressWindow::install_progress(package, progress);
+
+  ACQUIRE_LOCK(_progress_lock);
+  _progress = progress;
+  RELEASE_LOCK(_progress_lock);
+
+  // Post a silly message to spin the message loop.
+  PostThreadMessage(_thread_id, WM_USER, 0, 0);
+
+  if (!_thread_running) {
+    _inst->request_stop();
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DWinProgressWindow::start_thraed
+//       Access: Private
+//  Description: Spawns the sub-thread.
+////////////////////////////////////////////////////////////////////
+void P3DWinProgressWindow::
+start_thread() {
+  _thread_continue = true;
+  _thread = CreateThread(NULL, 0, &win_thread_run, this, 0, &_thread_id);
+  if (_thread != NULL) {
+    _thread_running = true;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DWinProgressWindow::stop_thraed
+//       Access: Private
+//  Description: Terminates and joins the sub-thread.
+////////////////////////////////////////////////////////////////////
+void P3DWinProgressWindow::
+stop_thread() {
+  _thread_continue = false;
+  // Post a silly message to spin the message loop.
+  PostThreadMessage(_thread_id, WM_USER, 0, 0);
+
+  WaitForSingleObject(_thread, INFINITE);
+  CloseHandle(_thread);
+  _thread = NULL;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DWinProgressWindow::thread_run
+//       Access: Private
+//  Description: The sub-thread's main run method.
+////////////////////////////////////////////////////////////////////
+void P3DWinProgressWindow::
+thread_run() {
+  make_window();
+
+  double last_progress = -1.0;
+
+  _loop_started = GetTickCount();
+  MSG msg;
+  int retval;
+  retval = GetMessage(&msg, NULL, 0, 0);
+  while (retval != 0 && _thread_continue) {
+    if (retval == -1) {
+      cerr << "Error processing message queue.\n";
+      break;
+    }
+    TranslateMessage(&msg);
+    DispatchMessage(&msg);
+
+    {
+      ACQUIRE_LOCK(_progress_lock);
+      double new_progress = _progress;
+      RELEASE_LOCK(_progress_lock);
+
+      if (new_progress != last_progress) {
+        if (_progress_bar == NULL) {
+          // Is it time to create the progress bar?
+          int now = GetTickCount();
+          if (now - _loop_started > 2000) {
+            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)(new_progress * 100.0), 0);
+          
+          last_progress = new_progress;
+        }
+      }
+    }
+
+    retval = GetMessage(&msg, NULL, 0, 0);
+  }
+
+  close_window();
+  _thread_running = false;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DWinProgressWindow::win_thread_run
+//       Access: Private, Static
+//  Description: The OS-specific thread callback function.
+////////////////////////////////////////////////////////////////////
+DWORD P3DWinProgressWindow::
+win_thread_run(LPVOID data) {
+  ((P3DWinProgressWindow *)data)->thread_run();
+  return 0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DWinProgressWindow::make_window
+//       Access: Private
+//  Description: Creates the window for displaying progress.  Runs
+//               within the sub-thread.
+////////////////////////////////////////////////////////////////////
+void P3DWinProgressWindow::
+make_window() {
+  WNDCLASS wc;
+
+  HINSTANCE application = GetModuleHandle(NULL);
+
+  static bool registered_class = false;
+  if (!registered_class) {
+    ZeroMemory(&wc, sizeof(WNDCLASS));
+    wc.lpfnWndProc = window_proc;
+    wc.hInstance = application;
+    wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
+    wc.lpszClassName = "panda3d_progress";
+    
+    if (!RegisterClass(&wc)) {
+      cerr << "Could not register window class!\n";
+    }
+    registered_class = true;
+  }
+  
+  int x = CW_USEDEFAULT;
+  int y = CW_USEDEFAULT;
+  if (_win_x != 0 && _win_y != 0) {
+    x = _win_x;
+    y = _win_y;
+  }
+  
+  int width = 320;
+  int height = 240;
+  if (_win_width != 0 && _win_height != 0) {
+    width = _win_width;
+    height = _win_height;
+  }
+
+  if (_window_type == P3D_WT_embedded) {
+    // Create an embedded window.
+    DWORD window_style = 
+      WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
+
+    HWND parent_hwnd = _parent_window._hwnd;
+
+    _hwnd = 
+      CreateWindow("panda3d_progress", "Panda3D", window_style,
+                   x, y, width, height,
+                   parent_hwnd, NULL, application, 0);
+    
+    if (!_hwnd) {
+      cerr << "Could not create embedded window!\n";
+      return;
+    }
+
+  } else {
+    // Create a toplevel window.
+    DWORD window_style = 
+      WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS |
+      WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
+      WS_SIZEBOX | WS_MAXIMIZEBOX;
+    
+    _hwnd = 
+      CreateWindow("panda3d_progress", "Panda3D", window_style,
+                   x, y, width, height,
+                   NULL, NULL, application, 0);
+    if (!_hwnd) {
+      cerr << "Could not create toplevel window!\n";
+      return;
+    }
+
+    // We don't initially show the toplevel window.  We'll show it
+    // when we create the actual progress bar, a few seconds later;
+    // otherwise, it might be distracting if the window pops up and
+    // then immediately disappears.
+  }
+}
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DWinProgressWindow::make_progress_bar
+//       Access: Private
+//  Description: Creates the progress bar and label.  Runs
+//               within the sub-thread.  This is done a few seconds
+//               after the main window is created, to give us a chance
+//               to launch quickly without bothering the user.
+////////////////////////////////////////////////////////////////////
+void P3DWinProgressWindow::
+make_progress_bar() {
+  if (_progress_bar != NULL) {
+    return;
+  }
+
+  HINSTANCE application = GetModuleHandle(NULL);
+  DWORD window_style = 
+    WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
+
+  RECT rect;
+  GetClientRect(_hwnd, &rect);
+  int width = rect.right - rect.left;
+  int height = rect.bottom - rect.top;
+
+  int bar_width = min((int)(width * 0.6), 400);
+  int bar_height = min((int)(height * 0.1), 24);
+  int bar_x = (width - bar_width) / 2;
+  int bar_y = (height - bar_height) / 2;
+
+  _progress_bar = 
+      CreateWindowEx(0, PROGRESS_CLASS, "", window_style,
+                     bar_x, bar_y, bar_width, bar_height,
+                     _hwnd, NULL, application, 0);
+
+  // Create a static text label.  What a major pain *this* is.
+  string text_string = "Installing " + _package->get_package_output_name();
+  const char *text = text_string.c_str();
+  HFONT font = (HFONT)GetStockObject(ANSI_VAR_FONT); 
+
+  HDC dc = GetDC(_hwnd);
+  SelectObject(dc, font);
+  SIZE text_size;
+  GetTextExtentPoint32(dc, text, strlen(text), &text_size);
+  ReleaseDC(_hwnd, dc);
+
+  int text_width = text_size.cx;
+  int text_height = text_size.cy;
+  int text_x = (width - text_width) / 2;
+  int text_y = bar_y - text_height - 2;
+
+  CreateWindowEx(0, "STATIC", text, SS_OWNERDRAW | window_style,
+                 text_x, text_y, text_width, text_height,
+                 _hwnd, NULL, application, 0);
+
+  // Ensure the main window is visible now.
+  ShowWindow(_hwnd, SW_SHOWNORMAL);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DWinProgressWindow::close_window
+//       Access: Private
+//  Description: Closes the window created above.
+////////////////////////////////////////////////////////////////////
+void P3DWinProgressWindow::
+close_window() {
+  if (_hwnd) {
+    ShowWindow(_hwnd, SW_HIDE);
+    CloseWindow(_hwnd);
+    _hwnd = NULL;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DWinProgressWindow::window_proc
+//       Access: Private, Static
+//  Description: The windows event-processing handler.
+////////////////////////////////////////////////////////////////////
+LONG P3DWinProgressWindow::
+window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
+  switch (msg) {
+  case WM_DESTROY:
+    PostQuitMessage(0);
+    break;
+
+  case WM_DRAWITEM:
+    {
+      DRAWITEMSTRUCT *dis = (DRAWITEMSTRUCT *)lparam;
+      FillRect(dis->hDC, &(dis->rcItem), WHITE_BRUSH);
+
+      static const int text_buffer_size = 512;
+      char text_buffer[text_buffer_size];
+      GetWindowText(dis->hwndItem, text_buffer, text_buffer_size);
+
+      HFONT font = (HFONT)GetStockObject(ANSI_VAR_FONT); 
+      SelectObject(dis->hDC, font);
+      SetBkColor(dis->hDC, 0x00ffffff);
+
+      DrawText(dis->hDC, text_buffer, -1, &(dis->rcItem), 
+               DT_BOTTOM | DT_CENTER | DT_SINGLELINE);
+    }
+  };
+
+  return DefWindowProc(hwnd, msg, wparam, lparam);
+}
+
+
+#endif  // _WIN32

+ 72 - 0
direct/src/plugin/p3dWinProgressWindow.h

@@ -0,0 +1,72 @@
+// Filename: p3dWinProgressWindow.h
+// Created by:  drose (17Jun09)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef P3DWINPROGRESSWINDOW_H
+#define P3DWINPROGRESSWINDOW_H
+
+#include "p3d_plugin_common.h"
+
+#ifdef _WIN32
+
+#include "p3dProgressWindow.h"
+#include "p3d_lock.h"
+
+#include <windows.h>
+
+////////////////////////////////////////////////////////////////////
+//       Class : P3DWinProgressWindow
+// Description : This is the Windows implementation of the
+//               initial-download window.
+////////////////////////////////////////////////////////////////////
+class P3DWinProgressWindow : public P3DProgressWindow {
+public:
+  P3DWinProgressWindow(P3DPackage *package, P3DSession *session, P3DInstance *inst);
+  virtual ~P3DWinProgressWindow();
+
+protected:
+  virtual void install_progress(P3DPackage *package, double progress);
+
+private:
+  void start_thread();
+  void stop_thread();
+
+private:
+  // These methods run only within the window thread.
+  void thread_run();
+  static DWORD WINAPI win_thread_run(LPVOID data);
+
+  void make_window();
+  void make_progress_bar();
+  void close_window();
+
+  static LONG WINAPI window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
+
+private:
+  double _progress;
+  LOCK _progress_lock;
+  int _loop_started;
+
+  bool _thread_continue;
+  bool _thread_running;
+  HANDLE _thread;
+  DWORD _thread_id;
+  HWND _hwnd;
+  HWND _progress_bar;
+};
+
+#include "p3dWinProgressWindow.I"
+
+#endif  // _WIN32
+
+#endif

+ 2 - 0
direct/src/plugin/p3d_plugin_composite1.cxx

@@ -5,4 +5,6 @@
 #include "p3dInstanceManager.cxx"
 #include "p3dMultifileReader.cxx"
 #include "p3dPackage.cxx"
+#include "p3dProgressWindow.cxx"
 #include "p3dSession.cxx"
+#include "p3dWinProgressWindow.cxx"

+ 5 - 1
direct/src/plugin/panda3d.cxx

@@ -562,7 +562,11 @@ int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) {
         inst = P3D_check_request(false);
       }
 
-      Thread::force_yield();
+      while (!PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) {
+        // spin, so we don't starve the download threads.
+        // TODO: use a better mechanism here.
+        Thread::force_yield();
+      }
       retval = GetMessage(&msg, NULL, 0, 0);
     }