Browse Source

move code to p3d directory for better organization

David Rose 16 years ago
parent
commit
d8859828ef

+ 5 - 5
direct/src/configfiles/panda3d.pdef

@@ -1,7 +1,7 @@
 # This file defines a number of standard "packages" that correspond to
 # This file defines a number of standard "packages" that correspond to
 # a Panda3D distribution.  These packages are built by passing this
 # a Panda3D distribution.  These packages are built by passing this
 # file to the ppackage utility, either as a packaged application, or
 # file to the ppackage utility, either as a packaged application, or
-# as the module direct.showutil.ppackage.
+# as the module direct.p3d.ppackage.
 
 
 # These packages are then downloaded by the Panda3D plugin and
 # These packages are then downloaded by the Panda3D plugin and
 # standalone runtime executable, and they contain the actual Panda3D
 # standalone runtime executable, and they contain the actual Panda3D
@@ -22,7 +22,7 @@ config display_name="Panda3D"
 
 
 # This is the key Python module that is imported at runtime to start
 # This is the key Python module that is imported at runtime to start
 # an application running.
 # an application running.
-module direct.showutil.runp3d
+module direct.p3d.AppRunner
 
 
 # These are additional Python modules that are needed by most Panda3D
 # These are additional Python modules that are needed by most Panda3D
 # applications.  It doesn't matter too much if we miss one or two
 # applications.  It doesn't matter too much if we miss one or two
@@ -59,7 +59,7 @@ freeze_dll runp3d_frozen
 
 
 # This is the main program that drives the plugin application.  It is
 # This is the main program that drives the plugin application.  It is
 # responsible for loading runp3d_frozen, above, and then importing
 # responsible for loading runp3d_frozen, above, and then importing
-# direct.showutil.runp3d, to start an application running.  Note that
+# direct.p3d.runp3d, to start an application running.  Note that
 # the .exe extension is automatically replaced with the
 # the .exe extension is automatically replaced with the
 # platform-specific extension appropriate for an executable.
 # platform-specific extension appropriate for an executable.
 file p3dpython.exe
 file p3dpython.exe
@@ -147,7 +147,7 @@ config hidden=1
 require panda3d
 require panda3d
 require egg
 require egg
 
 
-main_module direct.showutil.packp3d
+main_module direct.p3d.packp3d
 
 
 end_p3d packp3d
 end_p3d packp3d
 
 
@@ -164,6 +164,6 @@ config hidden=1
 require panda3d
 require panda3d
 require egg
 require egg
 
 
-main_module direct.showutil.ppackage
+main_module direct.p3d.ppackage
 
 
 end_p3d ppackage
 end_p3d ppackage

+ 0 - 0
direct/src/showutil/JavaScript.py → direct/src/p3d/JavaScript.py


+ 0 - 0
direct/src/showutil/Packager.py → direct/src/p3d/Packager.py


+ 0 - 0
direct/src/p3d/Sources.pp


+ 0 - 0
direct/src/p3d/__init__.py


+ 0 - 0
direct/src/showutil/make_contents.py → direct/src/p3d/make_contents.py


+ 1 - 1
direct/src/showutil/packp3d.py → direct/src/p3d/packp3d.py

@@ -47,7 +47,7 @@ import os
 import getopt
 import getopt
 import glob
 import glob
 import direct
 import direct
-from direct.showutil import Packager 
+from direct.p3d import Packager 
 from pandac.PandaModules import *
 from pandac.PandaModules import *
 
 
 class ArgumentError(StandardError):
 class ArgumentError(StandardError):

+ 2 - 2
direct/src/showutil/ppackage.py → direct/src/p3d/ppackage.py

@@ -86,8 +86,8 @@ import sys
 import getopt
 import getopt
 import os
 import os
 
 
-from direct.showutil import Packager
-from direct.showutil import make_contents
+from direct.p3d import Packager
+from direct.p3d import make_contents
 from pandac.PandaModules import *
 from pandac.PandaModules import *
 
 
 def usage(code, msg = ''):
 def usage(code, msg = ''):

+ 68 - 0
direct/src/p3d/runp3d.py

@@ -0,0 +1,68 @@
+#! /usr/bin/env python
+
+"""
+
+This tool will invoke the AppRunner to execute a packaged p3d
+application.  It requires that that the current Panda3D and Python
+versions match the version expected by the application.
+
+Normally, you do not need to use this tool; instead, use the provided
+standalone panda3d executable to invoke any p3d application.  Using
+panda3d will guarantee that the correct versions of Panda3D and Python
+are used to run the application.  However, there may be occasions when
+it is useful to use this tool to run the application with the current
+build instead of with its advertised version requirements.
+
+Usage:
+
+  runp3d.py app.p3d [args]
+
+The command-line arguments following the application name are passed
+into the application unchanged.
+
+See pack3d.p3d for an application that generates these p3d files.
+
+"""
+
+import sys
+import getopt
+from AppRunner import AppRunner, ArgumentError
+from direct.task.TaskManagerGlobal import taskMgr
+from pandac.PandaModules import Filename
+
+def parseSysArgs():
+    """ Handles sys.argv, if there are any local arguments, and
+    returns a new argv suitable for passing into the
+    application. """
+
+    # We prefix a "+" sign, following the GNU convention, to tell
+    # getopt not to parse options following the first non-option
+    # parameter.
+    opts, args = getopt.getopt(sys.argv[1:], '+h')
+
+    for option, value in opts:
+        if option == '-h':
+            print __doc__
+            sys.exit(1)
+
+    if not args or not args[0]:
+        raise ArgumentError, "No Panda app specified.  Use:\nrunp3d.py app.p3d"
+
+    arg0 = args[0]
+    p3dFilename = Filename.fromOsSpecific(arg0)
+    if p3dFilename.exists():
+        p3dFilename.makeAbsolute()
+        arg0 = p3dFilename.toOsSpecific()
+
+    return [arg0] + args[1:]
+
+if __name__ == '__main__':
+    runner = AppRunner()
+    runner.gotWindow = True
+    try:
+        argv = parseSysArgs()
+        runner.setP3DFilename(argv[0], argv = argv)
+    except ArgumentError, e:
+        print e.args[0]
+        sys.exit(1)
+    taskMgr.run()

+ 45 - 3
direct/src/plugin/binaryXml.cxx

@@ -27,6 +27,11 @@ enum NodeType {
   NT_text,
   NT_text,
 };
 };
 
 
+// These are both prime numbers, though I don't know if that really
+// matters.  Mainly, they're big random numbers.
+static const size_t length_nonce1 = 812311453;
+static const size_t length_nonce2 = 612811373;
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: write_xml_node
 //     Function: write_xml_node
 //  Description: Recursively writes a node and all of its children to
 //  Description: Recursively writes a node and all of its children to
@@ -53,7 +58,15 @@ write_xml_node(ostream &out, TiXmlNode *xnode) {
 
 
   const string &value = xnode->ValueStr();
   const string &value = xnode->ValueStr();
   size_t value_length = value.length();
   size_t value_length = value.length();
+  size_t value_proof = (value_length + length_nonce1) * length_nonce2;
+
+  // We write out not only value_length, but the same value again
+  // hashed by length_nonce1 and 2 (and truncated back to size_t),
+  // just to prove to the reader that we're still on the same page.
+  // We do this only on the top node; we don't bother for the nested
+  // nodes.
   out.write((char *)&value_length, sizeof(value_length));
   out.write((char *)&value_length, sizeof(value_length));
+  out.write((char *)&value_proof, sizeof(value_proof));
   out.write(value.data(), value_length);
   out.write(value.data(), value_length);
 
 
   if (type == NT_element) {
   if (type == NT_element) {
@@ -104,7 +117,8 @@ write_xml_node(ostream &out, TiXmlNode *xnode) {
 //               return value.  Returns NULL on error.
 //               return value.  Returns NULL on error.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 static TiXmlNode *
 static TiXmlNode *
-read_xml_node(istream &in, char *&buffer, size_t &buffer_length) {
+read_xml_node(istream &in, char *&buffer, size_t &buffer_length,
+              ostream &logfile) {
   NodeType type = (NodeType)in.get();
   NodeType type = (NodeType)in.get();
   if (type == NT_unknown) {
   if (type == NT_unknown) {
     return NULL;
     return NULL;
@@ -115,6 +129,34 @@ read_xml_node(istream &in, char *&buffer, size_t &buffer_length) {
   if (in.gcount() != sizeof(value_length)) {
   if (in.gcount() != sizeof(value_length)) {
     return NULL;
     return NULL;
   }
   }
+  size_t value_proof_expect = (value_length + length_nonce1) * length_nonce2;
+  size_t value_proof;
+  in.read((char *)&value_proof, sizeof(value_proof));
+  if (in.gcount() != sizeof(value_proof)) {
+    return NULL;
+  }
+  if (value_proof != value_proof_expect) {
+    // Hey, we ran into garbage: the proof value didn't match our
+    // expected proof value.
+    logfile << "Garbage on XML stream!\n";
+
+    // Print out the garbage; maybe it will help the developer figure
+    // out where it came from.
+    logfile << "Begin garbage:\n";
+    ostringstream strm;
+    strm.write((char *)&value_length, sizeof(value_length));
+    strm.write((char *)&value_proof, sizeof(value_proof));
+    logfile << strm.str();
+    for (size_t i = 0; i < 100; ++i) {
+      int ch = in.get();
+      if (ch != EOF) {
+        logfile.put(ch);
+      }
+    }
+    logfile << "\n";
+    logfile << "End garbage.\n";
+    return NULL;
+  }
 
 
   if (value_length > buffer_length) {
   if (value_length > buffer_length) {
     delete[] buffer;
     delete[] buffer;
@@ -187,7 +229,7 @@ read_xml_node(istream &in, char *&buffer, size_t &buffer_length) {
   
   
   while (got_child && in && !in.eof()) {
   while (got_child && in && !in.eof()) {
     // We have a child.
     // We have a child.
-    TiXmlNode *xchild = read_xml_node(in, buffer, buffer_length);
+    TiXmlNode *xchild = read_xml_node(in, buffer, buffer_length, logfile);
     if (xchild != NULL) {
     if (xchild != NULL) {
       xnode->LinkEndChild(xchild);
       xnode->LinkEndChild(xchild);
     }
     }
@@ -251,7 +293,7 @@ read_xml(istream &in, ostream &logfile) {
   // binary read.
   // binary read.
   size_t buffer_length = 128;
   size_t buffer_length = 128;
   char *buffer = new char[buffer_length];
   char *buffer = new char[buffer_length];
-  TiXmlNode *xnode = read_xml_node(in, buffer, buffer_length);
+  TiXmlNode *xnode = read_xml_node(in, buffer, buffer_length, logfile);
   delete[] buffer;
   delete[] buffer;
   if (xnode == NULL) {
   if (xnode == NULL) {
     return NULL;
     return NULL;

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

@@ -164,7 +164,7 @@ TiXmlElement *P3DFileParams::
 make_xml() {
 make_xml() {
   TiXmlElement *xfparams = new TiXmlElement("fparams");
   TiXmlElement *xfparams = new TiXmlElement("fparams");
 
 
-  xfparams->SetAttribute("p3d_filename", _p3d_filename.c_str());
+  xfparams->SetAttribute("p3d_filename", _p3d_filename);
 
 
   Tokens::const_iterator ti;
   Tokens::const_iterator ti;
   for (ti = _tokens.begin(); ti != _tokens.end(); ++ti) {
   for (ti = _tokens.begin(); ti != _tokens.end(); ++ti) {

+ 12 - 6
direct/src/plugin/p3dHost.cxx

@@ -35,7 +35,7 @@ P3DHost(const string &host_url) :
 
 
   _xcontents = NULL;
   _xcontents = NULL;
 
 
-  fill_host_dir();
+  determine_host_dir();
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -196,14 +196,17 @@ get_package_desc_file(FileSpec &desc_file,              // out
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: P3DHost::fill_host_dir
+//     Function: P3DHost::determine_host_dir
 //       Access: Private
 //       Access: Private
 //  Description: Hashes the host_url into a (mostly) unique directory
 //  Description: Hashes the host_url into a (mostly) unique directory
-//               string for this particular host.  Stores the result
-//               in _host_dir.
+//               string, which will be the root of the host's install
+//               tree.  Stores the result in _host_dir.
+//
+//               This code is duplicated in Python, in
+//               AppRunner.determineHostDir().
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void P3DHost::
 void P3DHost::
-fill_host_dir() {
+determine_host_dir() {
   P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
   P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
   _host_dir = inst_mgr->get_root_dir();
   _host_dir = inst_mgr->get_root_dir();
   _host_dir += "/";
   _host_dir += "/";
@@ -213,6 +216,9 @@ fill_host_dir() {
   // Look for a server name in the URL.  Including this string in the
   // Look for a server name in the URL.  Including this string in the
   // directory name makes it friendlier for people browsing the
   // directory name makes it friendlier for people browsing the
   // directory.
   // directory.
+
+  // We can't use URLSpec here, because we don't link with Panda3D.
+  // We have to do it by hand.
   size_t p = _host_url.find("://");
   size_t p = _host_url.find("://");
   if (p != string::npos) {
   if (p != string::npos) {
     size_t start = p + 3;
     size_t start = p + 3;
@@ -254,7 +260,7 @@ fill_host_dir() {
 
 
     // If we successfully got a hostname, we don't really need the
     // If we successfully got a hostname, we don't really need the
     // full hash.  We'll keep half of it.
     // full hash.  We'll keep half of it.
-    keep_hash = hash_size / 2;
+    keep_hash = keep_hash / 2;
   }
   }
 
 
   MD5_CTX ctx;
   MD5_CTX ctx;

+ 1 - 1
direct/src/plugin/p3dHost.h

@@ -51,7 +51,7 @@ public:
                              const string &package_version);
                              const string &package_version);
 
 
 private:
 private:
-  void fill_host_dir();
+  void determine_host_dir();
 
 
   static string standardize_filename(const string &filename);
   static string standardize_filename(const string &filename);
   static bool copy_file(const string &from_filename, const string &to_filename);
   static bool copy_file(const string &from_filename, const string &to_filename);

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

@@ -842,6 +842,9 @@ make_xml() {
   TiXmlElement *xinstance = new TiXmlElement("instance");
   TiXmlElement *xinstance = new TiXmlElement("instance");
   xinstance->SetAttribute("instance_id", _instance_id);
   xinstance->SetAttribute("instance_id", _instance_id);
 
 
+  P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
+  xinstance->SetAttribute("root_dir", inst_mgr->get_root_dir());
+
   TiXmlElement *xfparams = _fparams.make_xml();
   TiXmlElement *xfparams = _fparams.make_xml();
   xinstance->LinkEndChild(xfparams);
   xinstance->LinkEndChild(xfparams);
 
 
@@ -850,6 +853,12 @@ make_xml() {
     xinstance->LinkEndChild(xwparams);
     xinstance->LinkEndChild(xwparams);
   }
   }
 
 
+  Packages::const_iterator pi;
+  for (pi = _packages.begin(); pi != _packages.end(); ++pi) {
+    TiXmlElement *xpackage = (*pi)->make_xml();
+    xinstance->LinkEndChild(xpackage);
+  }
+
   return xinstance;
   return xinstance;
 }
 }
 
 

+ 24 - 0
direct/src/plugin/p3dPackage.cxx

@@ -129,6 +129,30 @@ remove_instance(P3DInstance *inst) {
   begin_info_download();
   begin_info_download();
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: P3DPackage::make_xml
+//       Access: Public
+//  Description: Returns a newly-allocated XML structure that
+//               corresponds to the package data within this
+//               instance.
+////////////////////////////////////////////////////////////////////
+TiXmlElement *P3DPackage::
+make_xml() {
+  TiXmlElement *xpackage = new TiXmlElement("package");
+
+  xpackage->SetAttribute("name", _package_name);
+  if (!_package_platform.empty()) {
+    xpackage->SetAttribute("platform", _package_platform);
+  }
+  if (!_package_version.empty()) {
+    xpackage->SetAttribute("version", _package_version);
+  }
+  xpackage->SetAttribute("host", _host->get_host_url());
+  xpackage->SetAttribute("install_dir", _package_dir);
+
+  return xpackage;
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: P3DPackage::begin_info_download
 //     Function: P3DPackage::begin_info_download
 //       Access: Private
 //       Access: Private

+ 2 - 0
direct/src/plugin/p3dPackage.h

@@ -60,6 +60,8 @@ public:
   void add_instance(P3DInstance *inst);
   void add_instance(P3DInstance *inst);
   void remove_instance(P3DInstance *inst);
   void remove_instance(P3DInstance *inst);
 
 
+  TiXmlElement *make_xml();
+
 private:
 private:
   enum DownloadType {
   enum DownloadType {
     DT_contents_file,
     DT_contents_file,

+ 70 - 9
direct/src/plugin/p3dPythonRun.cxx

@@ -127,14 +127,14 @@ run_python() {
   Py_DECREF(runp3d_frozen);
   Py_DECREF(runp3d_frozen);
 
 
   // So now we can import the module itself.
   // So now we can import the module itself.
-  PyObject *runp3d = PyImport_ImportModule("direct.showutil.runp3d");
-  if (runp3d == NULL) {
+  PyObject *app_runner_module = PyImport_ImportModule("direct.p3d.AppRunner");
+  if (app_runner_module == NULL) {
     PyErr_Print();
     PyErr_Print();
     return false;
     return false;
   }
   }
 
 
   // Get the pointers to the objects needed within the module.
   // Get the pointers to the objects needed within the module.
-  PyObject *app_runner_class = PyObject_GetAttrString(runp3d, "AppRunner");
+  PyObject *app_runner_class = PyObject_GetAttrString(app_runner_module, "AppRunner");
   if (app_runner_class == NULL) {
   if (app_runner_class == NULL) {
     PyErr_Print();
     PyErr_Print();
     return false;
     return false;
@@ -149,41 +149,41 @@ run_python() {
   Py_DECREF(app_runner_class);
   Py_DECREF(app_runner_class);
 
 
   // Get the UndefinedObject class.
   // Get the UndefinedObject class.
-  _undefined_object_class = PyObject_GetAttrString(runp3d, "UndefinedObject");
+  _undefined_object_class = PyObject_GetAttrString(app_runner_module, "UndefinedObject");
   if (_undefined_object_class == NULL) {
   if (_undefined_object_class == NULL) {
     PyErr_Print();
     PyErr_Print();
     return false;
     return false;
   }
   }
 
 
   // And the "Undefined" instance.
   // And the "Undefined" instance.
-  _undefined = PyObject_GetAttrString(runp3d, "Undefined");
+  _undefined = PyObject_GetAttrString(app_runner_module, "Undefined");
   if (_undefined == NULL) {
   if (_undefined == NULL) {
     PyErr_Print();
     PyErr_Print();
     return false;
     return false;
   }
   }
 
 
   // Get the ConcreteStruct class.
   // Get the ConcreteStruct class.
-  _concrete_struct_class = PyObject_GetAttrString(runp3d, "ConcreteStruct");
+  _concrete_struct_class = PyObject_GetAttrString(app_runner_module, "ConcreteStruct");
   if (_concrete_struct_class == NULL) {
   if (_concrete_struct_class == NULL) {
     PyErr_Print();
     PyErr_Print();
     return false;
     return false;
   }
   }
 
 
   // Get the BrowserObject class.
   // Get the BrowserObject class.
-  _browser_object_class = PyObject_GetAttrString(runp3d, "BrowserObject");
+  _browser_object_class = PyObject_GetAttrString(app_runner_module, "BrowserObject");
   if (_browser_object_class == NULL) {
   if (_browser_object_class == NULL) {
     PyErr_Print();
     PyErr_Print();
     return false;
     return false;
   }
   }
 
 
   // Get the global TaskManager.
   // Get the global TaskManager.
-  _taskMgr = PyObject_GetAttrString(runp3d, "taskMgr");
+  _taskMgr = PyObject_GetAttrString(app_runner_module, "taskMgr");
   if (_taskMgr == NULL) {
   if (_taskMgr == NULL) {
     PyErr_Print();
     PyErr_Print();
     return false;
     return false;
   }
   }
 
 
-  Py_DECREF(runp3d);
+  Py_DECREF(app_runner_module);
 
 
 
 
   // Construct a Python wrapper around our methods we need to expose to Python.
   // Construct a Python wrapper around our methods we need to expose to Python.
@@ -903,6 +903,14 @@ void P3DPythonRun::
 start_instance(P3DCInstance *inst, TiXmlElement *xinstance) {
 start_instance(P3DCInstance *inst, TiXmlElement *xinstance) {
   _instances[inst->get_instance_id()] = inst;
   _instances[inst->get_instance_id()] = inst;
 
 
+  set_instance_info(inst, xinstance);
+
+  TiXmlElement *xpackage = xinstance->FirstChildElement("package");
+  while (xpackage != (TiXmlElement *)NULL) {
+    add_package_info(inst, xpackage);
+    xpackage = xpackage->NextSiblingElement("package");
+  }
+
   TiXmlElement *xfparams = xinstance->FirstChildElement("fparams");
   TiXmlElement *xfparams = xinstance->FirstChildElement("fparams");
   if (xfparams != (TiXmlElement *)NULL) {
   if (xfparams != (TiXmlElement *)NULL) {
     set_p3d_filename(inst, xfparams);
     set_p3d_filename(inst, xfparams);
@@ -937,6 +945,59 @@ terminate_instance(int id) {
   terminate_session();
   terminate_session();
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: P3DPythonRun::set_instance_info
+//       Access: Private
+//  Description: Sets some global information about the instance.
+////////////////////////////////////////////////////////////////////
+void P3DPythonRun::
+set_instance_info(P3DCInstance *inst, TiXmlElement *xinstance) {
+  const char *root_dir = xinstance->Attribute("root_dir");
+  if (root_dir == NULL) {
+    root_dir = "";
+  }
+
+  PyObject *result = PyObject_CallMethod
+    (_runner, (char *)"setInstanceInfo", (char *)"s", root_dir);
+
+  if (result == NULL) {
+    PyErr_Print();
+  }
+  Py_XDECREF(result);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DPythonRun::add_package_info
+//       Access: Private
+//  Description: Adds some information about a pre-loaded package.
+////////////////////////////////////////////////////////////////////
+void P3DPythonRun::
+add_package_info(P3DCInstance *inst, TiXmlElement *xpackage) {
+  const char *name = xpackage->Attribute("name");
+  const char *platform = xpackage->Attribute("platform");
+  const char *version = xpackage->Attribute("version");
+  const char *host = xpackage->Attribute("host");
+  const char *install_dir = xpackage->Attribute("install_dir");
+  if (name == NULL || version == NULL || host == NULL) {
+    return;
+  }
+  if (platform == NULL) {
+    platform = "";
+  }
+  if (install_dir == NULL) {
+    install_dir = "";
+  }
+
+  PyObject *result = PyObject_CallMethod
+    (_runner, (char *)"addPackageInfo", (char *)"sssss",
+     name, platform, version, host, install_dir);
+
+  if (result == NULL) {
+    PyErr_Print();
+  }
+  Py_XDECREF(result);
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: P3DPythonRun::set_p3d_filename
 //     Function: P3DPythonRun::set_p3d_filename
 //       Access: Private
 //       Access: Private

+ 2 - 0
direct/src/plugin/p3dPythonRun.h

@@ -87,6 +87,8 @@ private:
 
 
   void start_instance(P3DCInstance *inst, TiXmlElement *xinstance);
   void start_instance(P3DCInstance *inst, TiXmlElement *xinstance);
   void terminate_instance(int id);
   void terminate_instance(int id);
+  void set_instance_info(P3DCInstance *inst, TiXmlElement *xinstance);
+  void add_package_info(P3DCInstance *inst, TiXmlElement *xpackage);
   void set_p3d_filename(P3DCInstance *inst, TiXmlElement *xfparams);
   void set_p3d_filename(P3DCInstance *inst, TiXmlElement *xfparams);
   void setup_window(int id, TiXmlElement *xwparams);
   void setup_window(int id, TiXmlElement *xwparams);
   void setup_window(P3DCInstance *inst, TiXmlElement *xwparams);
   void setup_window(P3DCInstance *inst, TiXmlElement *xwparams);

+ 0 - 4
direct/src/showutil/.gitignore

@@ -1,4 +0,0 @@
-/packp3d
-/packp3d.bat
-/runp3d
-/runp3d.bat

+ 0 - 516
direct/src/showutil/runp3d.py

@@ -1,516 +0,0 @@
-#! /usr/bin/env python
-
-"""
-
-This module is intended to be compiled into the Panda3D runtime
-distributable, but it can also be run directly via the Python
-interpreter.  It will run a Panda3D applet--a p3d file--that has
-previously been generated via packp3d.py.
-
-Usage:
-
-  runp3d.py app.p3d [args]
-
-The command-line arguments following the application name are passed
-into the application unchanged.
-
-See pack3d.py for a script that generates these p3d files.
-
-"""
-
-import sys
-from direct.showbase import VFSImporter
-from direct.showbase.DirectObject import DirectObject
-from pandac.PandaModules import VirtualFileSystem, Filename, Multifile, loadPrcFileData, unloadPrcFile, getModelPath, HTTPClient, Thread, WindowProperties, readXmlStream, ExecutionEnvironment
-from direct.stdpy import file
-from direct.task.TaskManagerGlobal import taskMgr
-from direct.showbase.MessengerGlobal import messenger
-from direct.showbase import AppRunnerGlobal
-
-# These imports are read by the C++ wrapper in p3dPythonRun.cxx.
-from direct.showutil.JavaScript import UndefinedObject, Undefined, ConcreteStruct, BrowserObject
-
-import os
-import types
-import __builtin__
-
-class ArgumentError(AttributeError):
-    pass
-
-class ScriptAttributes:
-    """ This dummy class serves as the root object for the scripting
-    interface.  The Python code can store objects and functions here
-    for direct inspection by the browser's JavaScript code. """
-    pass
-
-class AppRunner(DirectObject):
-    def __init__(self):
-        DirectObject.__init__(self)
-
-        self.sessionId = 0
-        self.packedAppEnvironmentInitialized = False
-        self.gotWindow = False
-        self.gotP3DFilename = False
-        self.started = False
-        self.windowOpened = False
-        self.windowPrc = None
-
-        self.fullDiskAccess = False
-
-        self.Undefined = Undefined
-        self.ConcreteStruct = ConcreteStruct
-
-        # This is per session.
-        self.nextScriptId = 0
-
-        # TODO: we need one of these per instance, not per session.
-        self.instanceId = None
-
-        # The mount point for the multifile.  For now, this is always
-        # the same, but when we move to multiple-instance sessions, it
-        # may have to be different for each instance.
-        self.multifileRoot = '/mf'
-
-        # The "main" object will be exposed to the DOM as a property
-        # of the plugin object; that is, document.pluginobject.main in
-        # JavaScript will be appRunner.main here.
-        self.main = ScriptAttributes()
-
-        # By default, we publish a stop() method so the browser can
-        # easy stop the plugin.
-        self.main.stop = self.stop
-
-        # This will be the browser's toplevel window DOM object;
-        # e.g. self.dom.document will be the document.
-        self.dom = None
-
-        # This is the list of expressions we will evaluate when
-        # self.dom gets assigned.
-        self.deferredEvals = []
-
-        # This is the default requestFunc that is installed if we
-        # never call setRequestFunc().
-        def defaultRequestFunc(*args):
-            if args[1] == 'notify':
-                # Quietly ignore notifies.
-                return
-            print "Ignoring request: %s" % (args,)
-        self.requestFunc = defaultRequestFunc
-
-        # Store our pointer so DirectStart-based apps can find us.
-        if AppRunnerGlobal.appRunner is None:
-            AppRunnerGlobal.appRunner = self
-
-        # We use this messenger hook to dispatch this startIfReady()
-        # call back to the main thread.
-        self.accept('startIfReady', self.startIfReady)
-            
-    def stop(self):
-        """ This method can be called by JavaScript to stop the
-        application. """
-
-        # We defer the actual exit for a few frames, so we don't raise
-        # an exception and invalidate the JavaScript call; and also to
-        # help protect against race conditions as the application
-        # shuts down.
-        taskMgr.doMethodLater(0.5, sys.exit, 'exit')
-
-    def setSessionId(self, sessionId):
-        """ This message should come in at startup. """
-        self.sessionId = sessionId
-        self.nextScriptId = self.sessionId * 1000 + 10000
-
-    def initPackedAppEnvironment(self):
-        """ This function sets up the Python environment suitably for
-        running a packed app.  It should only run once in any given
-        session (and it includes logic to ensure this). """
-
-        if self.packedAppEnvironmentInitialized:
-            return
-
-        self.packedAppEnvironmentInitialized = True
-
-        # We need to make sure sys.stdout maps to sys.stderr instead, so
-        # if someone makes an unadorned print command within Python code,
-        # it won't muck up the data stream between parent and child.
-        sys.stdout = sys.stderr
-
-        vfs = VirtualFileSystem.getGlobalPtr()
-
-        # Unmount directories we don't need.  This doesn't provide
-        # actual security, since it only disables this stuff for users
-        # who go through the vfs; a malicious programmer can always
-        # get to the underlying true file I/O operations.  Still, it
-        # can help prevent honest developers from accidentally getting
-        # stuck where they don't belong.
-        if not self.fullDiskAccess:
-            # Clear *all* the mount points, including "/", so that we
-            # no longer access the disk directly.
-            vfs.unmountAll()
-
-            # Make sure the directories on our standard Python path
-            # are mounted read-only, so we can still load Python.
-            # Note: read-only actually doesn't have any effect on the
-            # vfs right now; careless application code can still write
-            # to these directories inadvertently.
-            for dirname in sys.path:
-                dirname = Filename.fromOsSpecific(dirname)
-                if dirname.isDirectory():
-                    vfs.mount(dirname, dirname, vfs.MFReadOnly)
-
-            # Also mount some standard directories read-write
-            # (temporary and app-data directories).
-            tdir = Filename.temporary('', '')
-            for dirname in set([ tdir.getDirname(),
-                                 Filename.getTempDirectory().cStr(),
-                                 Filename.getUserAppdataDirectory().cStr(),
-                                 Filename.getCommonAppdataDirectory().cStr() ]):
-                vfs.mount(dirname, dirname, 0)
-
-            # And we might need the current working directory.
-            dirname = ExecutionEnvironment.getCwd()
-            vfs.mount(dirname, dirname, 0)
-
-        # Now set up Python to import this stuff.
-        VFSImporter.register()
-        sys.path = [ self.multifileRoot ] + sys.path
-
-        # Put our root directory on the model-path, too.
-        getModelPath().prependDirectory(self.multifileRoot)
-
-        # Replace the builtin open and file symbols so user code will get
-        # our versions by default, which can open and read files out of
-        # the multifile.
-        __builtin__.file = file.file
-        __builtin__.open = file.open
-        os.listdir = file.listdir
-        os.walk = file.walk
-
-        if not self.fullDiskAccess:
-            # Make "/mf" our "current directory", for running the multifiles
-            # we plan to mount there.
-            vfs.chdir(self.multifileRoot)
-
-    def startIfReady(self):
-        if self.started:
-            return
-
-        if self.gotWindow and self.gotP3DFilename:
-            self.started = True
-
-            # Now we can ignore future calls to startIfReady().
-            self.ignore('startIfReady')
-
-            # Hang a hook so we know when the window is actually opened.
-            self.acceptOnce('window-event', self.windowEvent)
-
-            # Look for the startup Python file.  This may be a magic
-            # filename (like "__main__", or any filename that contains
-            # invalid module characters), so we can't just import it
-            # directly; instead, we go through the low-level importer.
-
-            # If there's no p3d_info.xml file, we look for "main".
-            moduleName = 'main'
-            if self.p3dPackage:
-                mainName = self.p3dPackage.Attribute('main_module')
-                if mainName:
-                    moduleName = mainName
-
-            root = self.multifileRoot
-            if '.' in moduleName:
-                root += '/' + '/'.join(moduleName.split('.')[:-1])
-            v = VFSImporter.VFSImporter(root)
-            loader = v.find_module(moduleName)
-            if not loader:
-                message = "No %s found in application." % (moduleName)
-                raise StandardError, message
-            
-            main = loader.load_module(moduleName)
-            if hasattr(main, 'main') and callable(main.main):
-                main.main(self)
-
-    def getPandaScriptObject(self):
-        """ Called by the browser to query the Panda instance's
-        toplevel scripting object, for querying properties in the
-        Panda instance.  The attributes on this object are mapped to
-        document.pluginobject.main within the DOM. """
-
-        return self.main
-
-    def setBrowserScriptObject(self, dom):
-        """ Called by the browser to supply the browser's toplevel DOM
-        object, for controlling the JavaScript and the document in the
-        same page with the Panda3D plugin. """
-
-        self.dom = dom
-
-        # Now evaluate any deferred expressions.
-        for expression in self.deferredEvals:
-            self.scriptRequest('eval', self.dom, value = expression,
-                               needsResponse = False)
-        self.deferredEvals = []
-
-    def setP3DFilename(self, p3dFilename, tokens = [], argv = [],
-                       instanceId = None):
-        # One day we will have support for multiple instances within a
-        # Python session.  Against that day, we save the instance ID
-        # for this instance.
-        self.instanceId = instanceId
-
-        self.tokens = tokens
-        self.tokenDict = dict(tokens)
-        self.argv = argv
-
-        # Also store the arguments on sys, for applications that
-        # aren't instance-ready.
-        sys.argv = argv
-
-        # Tell the browser that Python is up and running, and ready to
-        # respond to queries.
-        self.notifyRequest('onpythonload')
-
-        # Now go load the applet.
-        fname = Filename.fromOsSpecific(p3dFilename)
-        vfs = VirtualFileSystem.getGlobalPtr()
-
-        if not vfs.exists(fname):
-            raise ArgumentError, "No such file: %s" % (p3dFilename)
-
-        fname.makeAbsolute()
-        mf = Multifile()
-        if not mf.openRead(fname):
-            raise ArgumentError, "Not a Panda Multifile: %s" % (p3dFilename)
-
-        # Now load the p3dInfo file.
-        self.p3dInfo = None
-        self.p3dPackage = None
-        i = mf.findSubfile('p3d_info.xml')
-        if i >= 0:
-            stream = mf.openReadSubfile(i)
-            self.p3dInfo = readXmlStream(stream)
-            mf.closeReadSubfile(stream)
-        if self.p3dInfo:
-            self.p3dPackage = self.p3dInfo.FirstChildElement('package')
-
-        if self.p3dPackage:
-            fullDiskAccess = self.p3dPackage.Attribute('full_disk_access')
-            try:
-                self.fullDiskAccess = int(fullDiskAccess or '')
-            except ValueError:
-                pass
-
-        self.initPackedAppEnvironment()
-
-        # Mount the Multifile under /mf, by convention.
-        vfs.mount(mf, self.multifileRoot, vfs.MFReadOnly)
-        VFSImporter.freeze_new_modules(mf, self.multifileRoot)
-
-        # Load any prc files in the root.  We have to load them
-        # explicitly, since the ConfigPageManager can't directly look
-        # inside the vfs.  Use the Multifile interface to find the prc
-        # files, rather than vfs.scanDirectory(), so we only pick up the
-        # files in this particular multifile.
-        for f in mf.getSubfileNames():
-            fn = Filename(f)
-            if fn.getDirname() == '' and fn.getExtension() == 'prc':
-                pathname = '%s/%s' % (self.multifileRoot, f)
-                data = open(pathname, 'r').read()
-                loadPrcFileData(pathname, data)
-
-        self.gotP3DFilename = True
-
-        # Send this call to the main thread; don't call it directly.
-        messenger.send('startIfReady', taskChain = 'default')
-
-    def clearWindowPrc(self):
-        """ Clears the windowPrc file that was created in a previous
-        call to setupWindow(), if any. """
-        
-        if self.windowPrc:
-            unloadPrcFile(self.windowPrc)
-            self.windowPrc = None
-
-    def setupWindow(self, windowType, x, y, width, height,
-                    parent, subprocessWindow):
-        """ Applies the indicated window parameters to the prc
-        settings, for future windows; or applies them directly to the
-        main window if the window has already been opened. """
-
-        if self.started and base.win:
-            # If we've already got a window, this must be a
-            # resize/reposition request.
-            wp = WindowProperties()
-            if x or y or windowType == 'embedded':
-                wp.setOrigin(x, y)
-            if width or height:
-                wp.setSize(width, height)
-            if subprocessWindow:
-                wp.setSubprocessWindow(subprocessWindow)
-            base.win.requestProperties(wp)
-            return
-
-        # If we haven't got a window already, start 'er up.  Apply the
-        # requested setting to the prc file.
-
-        if windowType == 'hidden':
-            data = 'window-type none\n'
-        else:
-            data = 'window-type onscreen\n'
-
-        if windowType == 'fullscreen':
-            data += 'fullscreen 1\n'
-        else:
-            data += 'fullscreen 0\n'
-
-        if windowType == 'embedded':
-            data += 'parent-window-handle %s\nsubprocess-window %s\n' % (
-                parent, subprocessWindow)
-        else:
-            data += 'parent-window-handle 0\nsubprocess-window \n'
-
-        if x or y or windowType == 'embedded':
-            data += 'win-origin %s %s\n' % (x, y)
-        if width or height:
-            data += 'win-size %s %s\n' % (width, height)
-
-        self.clearWindowPrc()
-        self.windowPrc = loadPrcFileData("setupWindow", data)
-
-        self.gotWindow = True
-
-        # Send this call to the main thread; don't call it directly.
-        messenger.send('startIfReady', taskChain = 'default')
-
-    def setRequestFunc(self, func):
-        """ This method is called by the plugin at startup to supply a
-        function that can be used to deliver requests upstream, to the
-        plugin, and thereby to the browser. """
-        self.requestFunc = func
-
-    def sendRequest(self, request, *args):
-        """ Delivers a request to the browser via self.requestFunc.
-        This low-level function is not intended to be called directly
-        by user code. """
-        
-        assert self.requestFunc
-        return self.requestFunc(self.instanceId, request, args)
-
-    def windowEvent(self, win):
-        """ This method is called when we get a window event.  We
-        listen for this to detect when the window has been
-        successfully opened. """
-
-        if not self.windowOpened:
-            self.windowOpened = True
-
-            # Now that the window is open, we don't need to keep those
-            # prc settings around any more.
-            self.clearWindowPrc()
-
-            # Inform the plugin and browser.
-            self.notifyRequest('onwindowopen')
-
-    def notifyRequest(self, message):
-        """ Delivers a notify request to the browser.  This is a "this
-        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)
-
-    def evalScript(self, expression, needsResponse = False):
-        """ Evaluates an arbitrary JavaScript expression in the global
-        DOM space.  This may be deferred if necessary if needsResponse
-        is False and self.dom has not yet been assigned.  If
-        needsResponse is true, this waits for the value and returns
-        it, which means it cannot be deferred. """
-
-        if not self.dom:
-            # Defer the expression.
-            assert not needsResponse
-            self.deferredEvals.append(expression)
-        else:
-            # Evaluate it now.
-            return self.scriptRequest('eval', self.dom, value = expression,
-                                      needsResponse = needsResponse)
-        
-    def scriptRequest(self, operation, object, propertyName = '',
-                      value = None, needsResponse = True):
-        """ Issues a new script request to the browser.  This queries
-        or modifies one of the browser's DOM properties.
-        
-        operation may be one of [ 'get_property', 'set_property',
-        'call', 'evaluate' ].
-
-        object is the browser object to manipulate, or the scope in
-        which to evaluate the expression.
-
-        propertyName is the name of the property to manipulate, if
-        relevant (set to None for the default method name).
-
-        value is the new value to assign to the property for
-        set_property, or the parameter list for call, or the string
-        expression for evaluate.
-
-        If needsResponse is true, this method will block until the
-        return value is received from the browser, and then it returns
-        that value.  Otherwise, it returns None immediately, without
-        waiting for the browser to process the request.
-        """
-        uniqueId = self.nextScriptId
-        self.nextScriptId = (self.nextScriptId + 1) % 0xffffffff
-        self.sendRequest('script', operation, object,
-                         propertyName, value, needsResponse, uniqueId)
-
-        if needsResponse:
-            # Now wait for the response to come in.
-            result = self.sendRequest('wait_script_response', uniqueId)
-            return result
-
-    def dropObject(self, objectId):
-        """ Inform the parent process that we no longer have an
-        interest in the P3D_object corresponding to the indicated
-        objectId. """
-
-        self.sendRequest('drop_p3dobj', objectId)
-
-    def parseSysArgs(self):
-        """ Handles sys.argv, if there are any local arguments, and
-        returns a new argv suitable for passing into the
-        application. """
-        
-        import getopt
-
-        # We prefix a "+" sign, following the GNU convention, to tell
-        # getopt not to parse options following the first non-option
-        # parameter.
-        opts, args = getopt.getopt(sys.argv[1:], '+h')
-
-        for option, value in opts:
-            if option == '-h':
-                print __doc__
-                sys.exit(1)
-
-        if not args or not args[0]:
-            raise ArgumentError, "No Panda app specified.  Use:\nrunp3d.py app.p3d"
-
-        arg0 = args[0]
-        p3dFilename = Filename.fromOsSpecific(arg0)
-        if p3dFilename.exists():
-            p3dFilename.makeAbsolute()
-            arg0 = p3dFilename.toOsSpecific()
-
-        return [arg0] + args[1:]
-
-if __name__ == '__main__':
-    runner = AppRunner()
-    runner.gotWindow = True
-    try:
-        argv = runner.parseSysArgs()
-        runner.setP3DFilename(argv[0], argv = argv)
-    except ArgumentError, e:
-        print e.args[0]
-        sys.exit(1)
-    taskMgr.run()