Browse Source

beginning Mozilla plugin integration

David Rose 16 years ago
parent
commit
ca983e8ece
41 changed files with 2126 additions and 269 deletions
  1. 0 21
      direct/src/plugin/Sources.pp
  2. 8 12
      direct/src/plugin/handleStreamBuf.cxx
  3. 145 0
      direct/src/plugin/load_plugin_src.cxx
  4. 31 0
      direct/src/plugin/load_plugin_src.h
  5. 38 0
      direct/src/plugin/p3dCInstance.cxx
  6. 3 0
      direct/src/plugin/p3dCInstance.h
  7. 2 2
      direct/src/plugin/p3dDownload.cxx
  8. 1 1
      direct/src/plugin/p3dFileDownload.cxx
  9. 17 6
      direct/src/plugin/p3dInstance.cxx
  10. 1 0
      direct/src/plugin/p3dInstance.h
  11. 4 4
      direct/src/plugin/p3dInstanceManager.cxx
  12. 10 10
      direct/src/plugin/p3dMultifileReader.cxx
  13. 29 29
      direct/src/plugin/p3dPackage.cxx
  14. 3 3
      direct/src/plugin/p3dProgressWindow.cxx
  15. 23 18
      direct/src/plugin/p3dPythonRun.cxx
  16. 3 3
      direct/src/plugin/p3dSession.I
  17. 20 20
      direct/src/plugin/p3dSession.cxx
  18. 3 3
      direct/src/plugin/p3dSession.h
  19. 4 4
      direct/src/plugin/p3dWinProgressWindow.cxx
  20. 22 1
      direct/src/plugin/p3d_plugin.cxx
  21. 23 11
      direct/src/plugin/p3d_plugin.h
  22. 6 1
      direct/src/plugin/p3d_plugin_common.h
  23. 30 0
      direct/src/plugin_npapi/Sources.pp
  24. 320 0
      direct/src/plugin_npapi/np_entry.cpp
  25. 215 0
      direct/src/plugin_npapi/npn_gate.cpp
  26. 358 0
      direct/src/plugin_npapi/npp_gate.cpp
  27. 9 0
      direct/src/plugin_npapi/nppanda3d.def
  28. 56 0
      direct/src/plugin_npapi/nppanda3d.rc
  29. 52 0
      direct/src/plugin_npapi/nppanda3d_common.h
  30. 4 0
      direct/src/plugin_npapi/nppanda3d_composite1.cxx
  31. 65 0
      direct/src/plugin_npapi/nppanda3d_startup.cxx
  32. 22 0
      direct/src/plugin_npapi/nppanda3d_startup.h
  33. 150 0
      direct/src/plugin_npapi/npplat.h
  34. 96 0
      direct/src/plugin_npapi/pluginbase.h
  35. 14 0
      direct/src/plugin_npapi/ppInstance.I
  36. 136 0
      direct/src/plugin_npapi/ppInstance.cxx
  37. 68 0
      direct/src/plugin_npapi/ppInstance.h
  38. 24 0
      direct/src/plugin_standalone/Sources.pp
  39. 42 112
      direct/src/plugin_standalone/panda3d.cxx
  40. 57 8
      direct/src/showbase/RunAppMF.py
  41. 12 0
      direct/src/showbase/ShowBase.py

+ 0 - 21
direct/src/plugin/Sources.pp

@@ -64,24 +64,3 @@
     p3dPythonRun.cxx p3dPythonRun.h p3dPythonRun.I
     p3dPythonRun.cxx p3dPythonRun.h p3dPythonRun.I
 
 
 #end bin_target
 #end bin_target
-
-#begin bin_target
-  #define USE_PACKAGES openssl zlib
-  #define TARGET panda3d
-
-  #define OTHER_LIBS \
-    prc:c dtoolutil:c dtoolbase:c dtool:m \
-    interrogatedb:c dconfig:c dtoolconfig:m \
-    express:c downloader:c pandaexpress:m \
-    pstatclient:c pandabase:c linmath:c putil:c \
-    pipeline:c panda:m \
-    pystub
-
-  #define OSX_SYS_FRAMEWORKS Foundation AppKit
-
-  #define SOURCES \
-    panda3d.cxx
-
-  #define WIN_SYS_LIBS user32.lib gdi32.lib shell32.lib
-
-#end bin_target

+ 8 - 12
direct/src/plugin/handleStreamBuf.cxx

@@ -260,10 +260,9 @@ read_chars(char *start, size_t length) {
   if (!success) {
   if (!success) {
     DWORD error = GetLastError();
     DWORD error = GetLastError();
     if (error != ERROR_HANDLE_EOF && error != ERROR_BROKEN_PIPE) {
     if (error != ERROR_HANDLE_EOF && error != ERROR_BROKEN_PIPE) {
-      cerr
-        << "Error reading " << length
-        << " bytes, windows error code 0x" << hex
-        << error << dec << ".\n";
+      cerr << "Error reading " << length
+           << " bytes, windows error code 0x" << hex
+           << error << dec << ".\n";
       return 0;
       return 0;
     }
     }
   }
   }
@@ -274,8 +273,7 @@ read_chars(char *start, size_t length) {
   // Posix case.
   // Posix case.
   ssize_t result = ::read(_handle, start, length);
   ssize_t result = ::read(_handle, start, length);
   if (result < 0) {
   if (result < 0) {
-    cerr
-      << "Error reading " << length << " bytes\n";
+    cerr << "Error reading " << length << " bytes\n";
     return 0;
     return 0;
   }
   }
 
 
@@ -313,10 +311,9 @@ write_chars(const char *start, size_t length) {
   if (!success) {
   if (!success) {
     DWORD error = GetLastError();
     DWORD error = GetLastError();
     if (error != ERROR_NO_DATA && error != ERROR_BROKEN_PIPE) {
     if (error != ERROR_NO_DATA && error != ERROR_BROKEN_PIPE) {
-      cerr
-        << "Error writing " << length
-        << " bytes, windows error code 0x" << hex
-        << error << dec << ".\n";
+      cerr << "Error writing " << length
+           << " bytes, windows error code 0x" << hex
+           << error << dec << ".\n";
     }
     }
     return bytes_written;
     return bytes_written;
   }
   }
@@ -329,8 +326,7 @@ write_chars(const char *start, size_t length) {
     ssize_t result = ::write(_handle, start, remaining);
     ssize_t result = ::write(_handle, start, remaining);
     if (result < 0) {
     if (result < 0) {
       if (errno != EPIPE) {
       if (errno != EPIPE) {
-        cerr
-          << "Error writing " << remaining << " bytes\n";
+        cerr << "Error writing " << remaining << " bytes\n";
       }
       }
       return length - remaining;
       return length - remaining;
     }
     }

+ 145 - 0
direct/src/plugin/load_plugin_src.cxx

@@ -0,0 +1,145 @@
+// Filename: load_plugin_src.cxx
+// Created by:  drose (19Jun09)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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."
+//
+////////////////////////////////////////////////////////////////////
+
+
+// This code is used in the plugin_standalone directory, and also in
+// the plugin_npapi directory.  To facilitate that code re-use with
+// minimal structural overhead, it is designed to be simply #included
+// into the different source files.
+
+#ifdef _WIN32
+static const string dll_ext = ".dll";
+#elif defined(__APPLE__)
+static const string dll_ext = ".dylib";
+#else
+static const string dll_ext = ".so";
+#endif
+
+static const string default_plugin_filename = "libp3d_plugin";
+
+P3D_initialize_func *P3D_initialize;
+P3D_free_string_func *P3D_free_string;
+P3D_create_instance_func *P3D_create_instance;
+P3D_instance_finish_func *P3D_instance_finish;
+P3D_instance_has_property_func *P3D_instance_has_property;
+P3D_instance_get_property_func *P3D_instance_get_property;
+P3D_instance_set_property_func *P3D_instance_set_property;
+P3D_instance_get_request_func *P3D_instance_get_request;
+P3D_check_request_func *P3D_check_request;
+P3D_request_finish_func *P3D_request_finish;
+P3D_instance_feed_url_stream_func *P3D_instance_feed_url_stream;
+
+#ifdef _WIN32
+static HMODULE module;
+#endif
+
+
+
+static void
+unload_plugin() {
+#ifdef _WIN32
+  FreeLibrary(module);
+  module = NULL;
+#else 
+  // TODO: unload_dso
+#endif
+  
+  P3D_initialize = NULL;
+  P3D_free_string = NULL;
+  P3D_create_instance = NULL;
+  P3D_instance_finish = NULL;
+  P3D_instance_has_property = NULL;
+  P3D_instance_get_property = NULL;
+  P3D_instance_set_property = NULL;
+  P3D_instance_get_request = NULL;
+  P3D_check_request = NULL;
+  P3D_request_finish = NULL;
+  P3D_instance_feed_url_stream = NULL;
+}
+
+static bool
+load_plugin(const string &p3d_plugin_filename) {
+  string filename = p3d_plugin_filename;
+  if (filename.empty()) {
+    // Look for the plugin along the path.
+    filename = default_plugin_filename + dll_ext;
+  }
+
+#ifdef _WIN32
+  module = LoadLibrary(filename.c_str());
+  if (module == NULL) {
+    // Couldn't load the DLL.
+    return false;
+  }
+
+  // Now get all of the function pointers.
+  P3D_initialize = (P3D_initialize_func *)GetProcAddress(module, "P3D_initialize");  
+  P3D_free_string = (P3D_free_string_func *)GetProcAddress(module, "P3D_free_string");  
+  P3D_create_instance = (P3D_create_instance_func *)GetProcAddress(module, "P3D_create_instance");  
+  P3D_instance_finish = (P3D_instance_finish_func *)GetProcAddress(module, "P3D_instance_finish");  
+  P3D_instance_has_property = (P3D_instance_has_property_func *)GetProcAddress(module, "P3D_instance_has_property");  
+  P3D_instance_get_property = (P3D_instance_get_property_func *)GetProcAddress(module, "P3D_instance_get_property");  
+  P3D_instance_set_property = (P3D_instance_set_property_func *)GetProcAddress(module, "P3D_instance_set_property");  
+  P3D_instance_get_request = (P3D_instance_get_request_func *)GetProcAddress(module, "P3D_instance_get_request");  
+  P3D_check_request = (P3D_check_request_func *)GetProcAddress(module, "P3D_check_request");  
+  P3D_request_finish = (P3D_request_finish_func *)GetProcAddress(module, "P3D_request_finish");  
+  P3D_instance_feed_url_stream = (P3D_instance_feed_url_stream_func *)GetProcAddress(module, "P3D_instance_feed_url_stream");  
+
+#else  // _WIN32
+  // Posix case.
+  void *module = dlopen(filename.c_str(), RTLD_NOW | RTLD_LOCAL);
+  if (module == NULL) {
+    // Couldn't load the .so.
+    return false;
+  }
+  
+  // Now get all of the function pointers.
+  P3D_initialize = (P3D_initialize_func *)dlsym(module, "P3D_initialize");  
+  P3D_free_string = (P3D_free_string_func *)dlsym(module, "P3D_free_string");  
+  P3D_create_instance = (P3D_create_instance_func *)dlsym(module, "P3D_create_instance");  
+  P3D_instance_finish = (P3D_instance_finish_func *)dlsym(module, "P3D_instance_finish");  
+  P3D_instance_has_property = (P3D_instance_has_property_func *)dlsym(module, "P3D_instance_has_property");  
+  P3D_instance_get_property = (P3D_instance_get_property_func *)dlsym(module, "P3D_instance_get_property");  
+  P3D_instance_set_property = (P3D_instance_set_property_func *)dlsym(module, "P3D_instance_set_property");  
+  P3D_instance_get_request = (P3D_instance_get_request_func *)dlsym(module, "P3D_instance_get_request");  
+  P3D_check_request = (P3D_check_request_func *)dlsym(module, "P3D_check_request");  
+  P3D_request_finish = (P3D_request_finish_func *)dlsym(module, "P3D_request_finish");  
+  P3D_instance_feed_url_stream = (P3D_instance_feed_url_stream_func *)dlsym(module, "P3D_instance_feed_url_stream");  
+
+#endif  // _WIN32
+
+  // Ensure that all of the function pointers have been found.
+  if (P3D_initialize == NULL ||
+      P3D_free_string == NULL ||
+      P3D_create_instance == NULL ||
+      P3D_instance_finish == NULL ||
+      P3D_instance_has_property == NULL ||
+      P3D_instance_get_property == NULL ||
+      P3D_instance_set_property == NULL ||
+      P3D_instance_get_request == NULL ||
+      P3D_check_request == NULL ||
+      P3D_request_finish == NULL ||
+      P3D_instance_feed_url_stream == NULL) {
+    return false;
+  }
+
+  // Successfully loaded.
+  if (!P3D_initialize(P3D_API_VERSION, "c:/cygwin/home/drose/t0.log")) {
+    // Oops, failure to initialize.
+    unload_plugin();
+    return false;
+  }
+
+  return true;
+}

+ 31 - 0
direct/src/plugin/load_plugin_src.h

@@ -0,0 +1,31 @@
+// Filename: load_plugin_src.h
+// Created by:  drose (19Jun09)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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."
+//
+////////////////////////////////////////////////////////////////////
+
+
+// This code is used in the plugin_standalone directory, and also in
+// the plugin_npapi directory.  To facilitate that code re-use with
+// minimal structural overhead, it is designed to be simply #included
+// into the different source files.
+
+extern P3D_initialize_func *P3D_initialize;
+extern P3D_free_string_func *P3D_free_string;
+extern P3D_create_instance_func *P3D_create_instance;
+extern P3D_instance_finish_func *P3D_instance_finish;
+extern P3D_instance_has_property_func *P3D_instance_has_property;
+extern P3D_instance_get_property_func *P3D_instance_get_property;
+extern P3D_instance_set_property_func *P3D_instance_set_property;
+extern P3D_instance_get_request_func *P3D_instance_get_request;
+extern P3D_check_request_func *P3D_check_request;
+extern P3D_request_finish_func *P3D_request_finish;
+extern P3D_instance_feed_url_stream_func *P3D_instance_feed_url_stream;

+ 38 - 0
direct/src/plugin/p3dCInstance.cxx

@@ -58,6 +58,23 @@ P3DCInstance(TiXmlElement *xinstance) :
     _parent_window._hwnd = (HWND)hwnd;
     _parent_window._hwnd = (HWND)hwnd;
   }
   }
 #endif
 #endif
+
+  TiXmlElement *xtoken = xinstance->FirstChildElement("token");
+  while (xtoken != NULL) {
+    Token token;
+    const char *keyword = xtoken->Attribute("keyword");
+    if (keyword != NULL) {
+      token._keyword = keyword;
+    }
+
+    const char *value = xtoken->Attribute("value");
+    if (value != NULL) {
+      token._value = value;
+    }
+
+    _tokens.push_back(token);
+    xtoken = xtoken->NextSiblingElement("token");
+  }
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -68,3 +85,24 @@ P3DCInstance(TiXmlElement *xinstance) :
 P3DCInstance::
 P3DCInstance::
 ~P3DCInstance() {
 ~P3DCInstance() {
 }
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DCInstance::get_py_tokens
+//       Access: Public
+//  Description: Returns a Python list object that corresponds to the
+//               tokens passed to this instance, expressed as a list
+//               of 2-tuples.  New instance.
+////////////////////////////////////////////////////////////////////
+PyObject *P3DCInstance::
+get_py_tokens() const {
+  PyObject *list = PyList_New(_tokens.size());
+
+  for (size_t i = 0; i < _tokens.size(); ++i) {
+    const Token &token = _tokens[i];
+    PyObject *tuple = Py_BuildValue("(ss)", token._keyword.c_str(), 
+                                    token._value.c_str());
+    PyList_SetItem(list, i, tuple);
+  }
+
+  return list;
+}

+ 3 - 0
direct/src/plugin/p3dCInstance.h

@@ -20,6 +20,7 @@
 #include "p3d_plugin.h"
 #include "p3d_plugin.h"
 #include "pvector.h"
 #include "pvector.h"
 
 
+#include <Python.h>
 #include <tinyxml.h>
 #include <tinyxml.h>
 
 
 class P3DSession;
 class P3DSession;
@@ -37,6 +38,8 @@ public:
   inline const string &get_p3d_filename() const;
   inline const string &get_p3d_filename() const;
   inline int get_instance_id() const;
   inline int get_instance_id() const;
 
 
+  PyObject *get_py_tokens() const;
+
 private:
 private:
   class Token {
   class Token {
   public:
   public:

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

@@ -129,7 +129,7 @@ void P3DDownload::
 download_progress() {
 download_progress() {
   time_t now = time(NULL);
   time_t now = time(NULL);
   if (now != _last_reported_time || true) {
   if (now != _last_reported_time || true) {
-    cerr << "Downloading " << get_url() << ": " 
+    nout << "Downloading " << get_url() << ": " 
          << int(get_download_progress() * 1000.0) / 10.0 << "\n";
          << int(get_download_progress() * 1000.0) / 10.0 << "\n";
     _last_reported_time = now;
     _last_reported_time = now;
   }
   }
@@ -145,6 +145,6 @@ download_progress() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void P3DDownload::
 void P3DDownload::
 download_finished(bool success) {
 download_finished(bool success) {
-  cerr << "Downloading " << get_url() << ": " 
+  nout << "Downloading " << get_url() << ": " 
        << int(get_download_progress() * 1000.0) / 10.0 << "\n";
        << int(get_download_progress() * 1000.0) / 10.0 << "\n";
 }
 }

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

@@ -47,7 +47,7 @@ bool P3DFileDownload::
 open_file() {
 open_file() {
   P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
   P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
   if (!inst_mgr->mkfile_public(_filename)) {
   if (!inst_mgr->mkfile_public(_filename)) {
-    cerr << "Unable to create " << _filename << "\n";
+    nout << "Unable to create " << _filename << "\n";
     return false;
     return false;
   }
   }
   
   

+ 17 - 6
direct/src/plugin/p3dInstance.cxx

@@ -41,7 +41,7 @@ P3DInstance(P3D_request_ready_func *func,
   _parent_window(parent_window)
   _parent_window(parent_window)
 {
 {
   fill_tokens(tokens, num_tokens);
   fill_tokens(tokens, num_tokens);
-  cerr << "instance, size = " << _win_width << " " << _win_height << "\n";
+  nout << "instance, size = " << _win_width << " " << _win_height << "\n";
 
 
   _instance_id = _next_instance_id;
   _instance_id = _next_instance_id;
   ++_next_instance_id;
   ++_next_instance_id;
@@ -72,6 +72,9 @@ P3DInstance::
   DESTROY_LOCK(_request_lock);
   DESTROY_LOCK(_request_lock);
 
 
   // TODO: empty _pending_requests queue and _downloads map.
   // TODO: empty _pending_requests queue and _downloads map.
+
+  // TODO: Is it possible for someone to delete an instance while a
+  // download is still running?  Who will crash when this happens?
 }
 }
 
 
 
 
@@ -158,7 +161,7 @@ get_request() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void P3DInstance::
 void P3DInstance::
 add_request(P3D_request *request) {
 add_request(P3D_request *request) {
-  cerr << "adding a request\n";
+  nout << "adding a request\n";
   assert(request->_instance == this);
   assert(request->_instance == this);
 
 
   ACQUIRE_LOCK(_request_lock);
   ACQUIRE_LOCK(_request_lock);
@@ -201,7 +204,7 @@ feed_url_stream(int unique_id,
                 size_t this_data_size) {
                 size_t this_data_size) {
   Downloads::iterator di = _downloads.find(unique_id);
   Downloads::iterator di = _downloads.find(unique_id);
   if (di == _downloads.end()) {
   if (di == _downloads.end()) {
-    cerr << "Unexpected feed_url_stream for " << unique_id << "\n";
+    nout << "Unexpected feed_url_stream for " << unique_id << "\n";
     // Don't know this request.
     // Don't know this request.
     return false;
     return false;
   }
   }
@@ -213,7 +216,7 @@ feed_url_stream(int unique_id,
 
 
   if (!download_ok || download->get_download_finished()) {
   if (!download_ok || download->get_download_finished()) {
     // All done.
     // All done.
-    cerr << "completed download " << unique_id << "\n";
+    nout << "completed download " << unique_id << "\n";
     _downloads.erase(di);
     _downloads.erase(di);
     delete download;
     delete download;
   }
   }
@@ -261,7 +264,7 @@ start_download(P3DDownload *download) {
   bool inserted = _downloads.insert(Downloads::value_type(download_id, download)).second;
   bool inserted = _downloads.insert(Downloads::value_type(download_id, download)).second;
   assert(inserted);
   assert(inserted);
 
 
-  cerr << "beginning download " << download_id << ": " << download->get_url()
+  nout << "beginning download " << download_id << ": " << download->get_url()
        << "\n";
        << "\n";
 
 
   P3D_request *request = new P3D_request;
   P3D_request *request = new P3D_request;
@@ -334,6 +337,15 @@ make_xml() {
     break;
     break;
   }
   }
 
 
+  Tokens::const_iterator ti;
+  for (ti = _tokens.begin(); ti != _tokens.end(); ++ti) {
+    const Token &token = (*ti);
+    TiXmlElement *xtoken = new TiXmlElement("token");
+    xtoken->SetAttribute("keyword", token._keyword.c_str());
+    xtoken->SetAttribute("value", token._value.c_str());
+    xinstance->LinkEndChild(xtoken);
+  }
+
   return xinstance;
   return xinstance;
 }
 }
 
 
@@ -356,4 +368,3 @@ fill_tokens(const P3D_token tokens[], size_t num_tokens) {
     _tokens.push_back(token);
     _tokens.push_back(token);
   }
   }
 }
 }
-

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

@@ -16,6 +16,7 @@
 #define P3DINSTANCE_H
 #define P3DINSTANCE_H
 
 
 #include "p3d_plugin_common.h"
 #include "p3d_plugin_common.h"
+#include "p3dFileDownload.h"
 
 
 #include <vector>
 #include <vector>
 #include <deque>
 #include <deque>

+ 4 - 4
direct/src/plugin/p3dInstanceManager.cxx

@@ -33,7 +33,7 @@ P3DInstanceManager *P3DInstanceManager::_global_ptr;
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 P3DInstanceManager::
 P3DInstanceManager::
 P3DInstanceManager() {
 P3DInstanceManager() {
-  cerr << "creating instance manager\n";
+  nout << "creating instance manager\n";
   _is_initialized = false;
   _is_initialized = false;
   _unique_session_index = 0;
   _unique_session_index = 0;
 
 
@@ -91,7 +91,7 @@ P3DInstanceManager::
 bool P3DInstanceManager::
 bool P3DInstanceManager::
 initialize() {
 initialize() {
   _root_dir = find_root_dir();
   _root_dir = find_root_dir();
-  cerr << "_root_dir = " << _root_dir << "\n";
+  nout << "_root_dir = " << _root_dir << "\n";
 
 
 #ifdef _WIN32
 #ifdef _WIN32
   _download_url = "http://10.196.143.118/~drose/p3d/";
   _download_url = "http://10.196.143.118/~drose/p3d/";
@@ -101,7 +101,7 @@ initialize() {
 #endif
 #endif
 
 
   if (_root_dir.empty()) {
   if (_root_dir.empty()) {
-    cerr << "Could not find root directory.\n";
+    nout << "Could not find root directory.\n";
     return false;
     return false;
   }
   }
 
 
@@ -487,7 +487,7 @@ find_root_dir() const {
   }
   }
 
 
   // Couldn't find a directory.  Bail.
   // Couldn't find a directory.  Bail.
-  cerr << "Couldn't find a root directory.\n";
+  nout << "Couldn't find a root directory.\n";
   return string();
   return string();
 
 
 #else  // _WIN32
 #else  // _WIN32

+ 10 - 10
direct/src/plugin/p3dMultifileReader.cxx

@@ -66,14 +66,14 @@ extract(const string &pathname, const string &to_dir,
 
 
   _in.open(pathname.c_str(), ios::in | ios::binary);
   _in.open(pathname.c_str(), ios::in | ios::binary);
   if (!_in) {
   if (!_in) {
-    cerr << "Couldn't open " << pathname << "\n";
+    nout << "Couldn't open " << pathname << "\n";
     return false;
     return false;
   }
   }
 
 
   for (size_t i = 0; i < _header_size; ++i) {
   for (size_t i = 0; i < _header_size; ++i) {
     int ch = _in.get();
     int ch = _in.get();
     if (ch != _header[i]) {
     if (ch != _header[i]) {
-      cerr << "Failed header check: " << pathname << "\n";
+      nout << "Failed header check: " << pathname << "\n";
       return false;
       return false;
     }
     }
   }
   }
@@ -81,13 +81,13 @@ extract(const string &pathname, const string &to_dir,
   unsigned int major = read_uint16();
   unsigned int major = read_uint16();
   unsigned int minor = read_uint16();
   unsigned int minor = read_uint16();
   if (major != _current_major_ver || minor != _current_minor_ver) {
   if (major != _current_major_ver || minor != _current_minor_ver) {
-    cerr << "Incompatible multifile version: " << pathname << "\n";
+    nout << "Incompatible multifile version: " << pathname << "\n";
     return false;
     return false;
   }
   }
 
 
   unsigned int scale = read_uint32();
   unsigned int scale = read_uint32();
   if (scale != 1) {
   if (scale != 1) {
-    cerr << "Unsupported scale factor in " << pathname << "\n";
+    nout << "Unsupported scale factor in " << pathname << "\n";
     return false;
     return false;
   }
   }
 
 
@@ -95,7 +95,7 @@ extract(const string &pathname, const string &to_dir,
   read_uint32();
   read_uint32();
 
 
   if (!read_index()) {
   if (!read_index()) {
-    cerr << "Error reading multifile index\n";
+    nout << "Error reading multifile index\n";
     return false;
     return false;
   }
   }
 
 
@@ -106,17 +106,17 @@ extract(const string &pathname, const string &to_dir,
   Subfiles::iterator si;
   Subfiles::iterator si;
   for (si = _subfiles.begin(); si != _subfiles.end(); ++si) {
   for (si = _subfiles.begin(); si != _subfiles.end(); ++si) {
     const Subfile &s = (*si);
     const Subfile &s = (*si);
-    cerr << s._filename << "\n";
+    nout << s._filename << "\n";
 
 
     string output_pathname = to_dir + "/" + s._filename;
     string output_pathname = to_dir + "/" + s._filename;
     if (!inst_mgr->mkfile_public(output_pathname)) {
     if (!inst_mgr->mkfile_public(output_pathname)) {
-      cerr << "Unable to create " << output_pathname << "\n";
+      nout << "Unable to create " << output_pathname << "\n";
       return false;
       return false;
     }
     }
 
 
     ofstream out(output_pathname.c_str(), ios::out | ios::binary);
     ofstream out(output_pathname.c_str(), ios::out | ios::binary);
     if (!out) {
     if (!out) {
-      cerr << "Unable to write to " << output_pathname << "\n";
+      nout << "Unable to write to " << output_pathname << "\n";
       return false;
       return false;
     }
     }
 
 
@@ -136,7 +136,7 @@ extract(const string &pathname, const string &to_dir,
     }
     }
 
 
     if (remaining_data != 0) {
     if (remaining_data != 0) {
-      cerr << "Unable to extract " << s._filename << "\n";
+      nout << "Unable to extract " << s._filename << "\n";
       return false;
       return false;
     }
     }
 
 
@@ -177,7 +177,7 @@ read_index() {
     s._length = read_uint32();
     s._length = read_uint32();
     unsigned int flags = read_uint16();
     unsigned int flags = read_uint16();
     if (flags != 0) {
     if (flags != 0) {
-      cerr << "Unsupported per-subfile options in multifile\n";
+      nout << "Unsupported per-subfile options in multifile\n";
       return false;
       return false;
     }
     }
     s._timestamp = read_uint32();
     s._timestamp = read_uint32();

+ 29 - 29
direct/src/plugin/p3dPackage.cxx

@@ -143,7 +143,7 @@ cancel_callback(Callback *callback) {
   if (ci != _callbacks.end()) {
   if (ci != _callbacks.end()) {
     _callbacks.erase(ci);
     _callbacks.erase(ci);
   } else {
   } else {
-    cerr << "Canceling unknown callback on " << _package_fullname << "\n";
+    nout << "Canceling unknown callback on " << _package_fullname << "\n";
   }
   }
 }
 }
 
 
@@ -175,7 +175,7 @@ desc_file_download_finished(bool success) {
 
 
   TiXmlDocument doc(_desc_file_pathname.c_str());
   TiXmlDocument doc(_desc_file_pathname.c_str());
   if (!doc.LoadFile()) {
   if (!doc.LoadFile()) {
-    cerr << "Couldn't read " << _desc_file_pathname << "\n";
+    nout << "Couldn't read " << _desc_file_pathname << "\n";
     report_done(false);
     report_done(false);
     return;
     return;
   }
   }
@@ -190,7 +190,7 @@ desc_file_download_finished(bool success) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void P3DPackage::
 void P3DPackage::
 got_desc_file(TiXmlDocument *doc, bool freshly_downloaded) {
 got_desc_file(TiXmlDocument *doc, bool freshly_downloaded) {
-  cerr << "got desc file\n";
+  nout << "got desc file\n";
 
 
   TiXmlElement *xpackage = doc->FirstChildElement("package");
   TiXmlElement *xpackage = doc->FirstChildElement("package");
   TiXmlElement *uncompressed_archive = NULL;
   TiXmlElement *uncompressed_archive = NULL;
@@ -224,7 +224,7 @@ got_desc_file(TiXmlDocument *doc, bool freshly_downloaded) {
     component = component->NextSiblingElement("component");
     component = component->NextSiblingElement("component");
   }
   }
 
 
-  cerr << "got " << _components.size() << " components\n";
+  nout << "got " << _components.size() << " components\n";
 
 
   // Verify all of the components.
   // Verify all of the components.
   bool all_components_ok = true;
   bool all_components_ok = true;
@@ -304,7 +304,7 @@ compressed_archive_download_finished(bool success) {
     download_compressed_archive(false);
     download_compressed_archive(false);
   }
   }
 
 
-  cerr << _compressed_archive._filename
+  nout << _compressed_archive._filename
        << " failed hash check after download\n";
        << " failed hash check after download\n";
   report_done(false);
   report_done(false);
 }
 }
@@ -316,28 +316,28 @@ compressed_archive_download_finished(bool success) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void P3DPackage::
 void P3DPackage::
 uncompress_archive() {
 uncompress_archive() {
-  cerr << "uncompressing " << _compressed_archive._filename << "\n";
+  nout << "uncompressing " << _compressed_archive._filename << "\n";
 
 
   string source_pathname = _package_dir + "/" + _compressed_archive._filename;
   string source_pathname = _package_dir + "/" + _compressed_archive._filename;
   string target_pathname = _package_dir + "/" + _uncompressed_archive._filename;
   string target_pathname = _package_dir + "/" + _uncompressed_archive._filename;
 
 
   ifstream source(source_pathname.c_str(), ios::in | ios::binary);
   ifstream source(source_pathname.c_str(), ios::in | ios::binary);
   if (!source) {
   if (!source) {
-    cerr << "Couldn't open " << source_pathname << "\n";
+    nout << "Couldn't open " << source_pathname << "\n";
     report_done(false);
     report_done(false);
     return;
     return;
   }
   }
 
 
   P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
   P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
   if (!inst_mgr->mkfile_public(target_pathname)) {
   if (!inst_mgr->mkfile_public(target_pathname)) {
-    cerr << "Unable to create " << target_pathname << "\n";
+    nout << "Unable to create " << target_pathname << "\n";
     report_done(false);
     report_done(false);
     return;
     return;
   }
   }
 
 
   ofstream target(target_pathname.c_str(), ios::out | ios::binary);
   ofstream target(target_pathname.c_str(), ios::out | ios::binary);
   if (!target) {
   if (!target) {
-    cerr << "Couldn't write to " << target_pathname << "\n";
+    nout << "Couldn't write to " << target_pathname << "\n";
     report_done(false);
     report_done(false);
     return;
     return;
   }
   }
@@ -369,7 +369,7 @@ uncompress_archive() {
 
 
   int result = inflateInit(&z);
   int result = inflateInit(&z);
   if (result < 0) {
   if (result < 0) {
-    cerr << z.msg << "\n";
+    nout << z.msg << "\n";
     report_done(false);
     report_done(false);
     return;
     return;
   }
   }
@@ -391,7 +391,7 @@ uncompress_archive() {
     if (z.avail_out < write_buffer_size) {
     if (z.avail_out < write_buffer_size) {
       target.write(write_buffer, write_buffer_size - z.avail_out);
       target.write(write_buffer, write_buffer_size - z.avail_out);
       if (!target) {
       if (!target) {
-        cerr << "Couldn't write entire file to " << target_pathname << "\n";
+        nout << "Couldn't write entire file to " << target_pathname << "\n";
         report_done(false);
         report_done(false);
         return;
         return;
       }
       }
@@ -414,7 +414,7 @@ uncompress_archive() {
       flush = Z_FINISH;
       flush = Z_FINISH;
 
 
     } else if (result < 0) {
     } else if (result < 0) {
-      cerr << z.msg << "\n";
+      nout << z.msg << "\n";
       inflateEnd(&z);
       inflateEnd(&z);
       report_done(false);
       report_done(false);
       return;
       return;
@@ -423,7 +423,7 @@ uncompress_archive() {
 
 
   result = inflateEnd(&z);
   result = inflateEnd(&z);
   if (result < 0) {
   if (result < 0) {
-    cerr << z.msg << "\n";
+    nout << z.msg << "\n";
     report_done(false);
     report_done(false);
     return;
     return;
   }
   }
@@ -432,7 +432,7 @@ uncompress_archive() {
   target.close();
   target.close();
 
 
   if (!_uncompressed_archive.full_verify(_package_dir)) {
   if (!_uncompressed_archive.full_verify(_package_dir)) {
-    cerr << "after uncompressing " << target_pathname
+    nout << "after uncompressing " << target_pathname
          << ", failed hash check\n";
          << ", failed hash check\n";
     report_done(false);
     report_done(false);
     return;
     return;
@@ -451,19 +451,19 @@ uncompress_archive() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void P3DPackage::
 void P3DPackage::
 extract_archive() {
 extract_archive() {
-  cerr << "extracting " << _uncompressed_archive._filename << "\n";
+  nout << "extracting " << _uncompressed_archive._filename << "\n";
 
 
   string source_pathname = _package_dir + "/" + _uncompressed_archive._filename;
   string source_pathname = _package_dir + "/" + _uncompressed_archive._filename;
   P3DMultifileReader reader;
   P3DMultifileReader reader;
   if (!reader.extract(source_pathname, _package_dir,
   if (!reader.extract(source_pathname, _package_dir,
                       this, download_portion + uncompress_portion, extract_portion)) {
                       this, download_portion + uncompress_portion, extract_portion)) {
-    cerr << "Failure extracting " << _uncompressed_archive._filename
+    nout << "Failure extracting " << _uncompressed_archive._filename
          << "\n";
          << "\n";
     report_done(false);
     report_done(false);
     return;
     return;
   }
   }
 
 
-  cerr << "done extracting\n";
+  nout << "done extracting\n";
   report_done(true);
   report_done(true);
 }
 }
 
 
@@ -490,7 +490,7 @@ report_progress(double progress) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void P3DPackage::
 void P3DPackage::
 report_done(bool success) {
 report_done(bool success) {
-  cerr << "report_done(" << success << "), "
+  nout << "report_done(" << success << "), "
        << _callbacks.size() << " callbacks\n";
        << _callbacks.size() << " callbacks\n";
   if (success) {
   if (success) {
     _ready = true;
     _ready = true;
@@ -740,33 +740,33 @@ quick_verify(const string &package_dir) const {
   string pathname = package_dir + "/" + _filename;
   string pathname = package_dir + "/" + _filename;
   struct stat st;
   struct stat st;
   if (stat(pathname.c_str(), &st) != 0) {
   if (stat(pathname.c_str(), &st) != 0) {
-    cerr << "file not found: " << _filename << "\n";
+    nout << "file not found: " << _filename << "\n";
     return false;
     return false;
   }
   }
 
 
   if (st.st_size != _size) {
   if (st.st_size != _size) {
     // If the size is wrong, the file fails.
     // If the size is wrong, the file fails.
-    cerr << "size wrong: " << _filename << "\n";
+    nout << "size wrong: " << _filename << "\n";
     return false;
     return false;
   }
   }
 
 
   if (st.st_mtime == _timestamp) {
   if (st.st_mtime == _timestamp) {
     // If the size is right and the timestamp is right, the file passes.
     // If the size is right and the timestamp is right, the file passes.
-    cerr << "file ok: " << _filename << "\n";
+    nout << "file ok: " << _filename << "\n";
     return true;
     return true;
   }
   }
 
 
-  cerr << "modification time wrong: " << _filename << "\n";
+  nout << "modification time wrong: " << _filename << "\n";
 
 
   // If the size is right but the timestamp is wrong, the file
   // If the size is right but the timestamp is wrong, the file
   // soft-fails.  We follow this up with a hash check.
   // soft-fails.  We follow this up with a hash check.
   if (!check_hash(pathname)) {
   if (!check_hash(pathname)) {
     // Hard fail, the hash is wrong.
     // Hard fail, the hash is wrong.
-    cerr << "hash check wrong: " << _filename << "\n";
+    nout << "hash check wrong: " << _filename << "\n";
     return false;
     return false;
   }
   }
 
 
-  cerr << "hash check ok: " << _filename << "\n";
+  nout << "hash check ok: " << _filename << "\n";
 
 
   // The hash is OK after all.  Change the file's timestamp back to
   // The hash is OK after all.  Change the file's timestamp back to
   // what we expect it to be, so we can quick-verify it successfully
   // what we expect it to be, so we can quick-verify it successfully
@@ -795,13 +795,13 @@ full_verify(const string &package_dir) const {
   string pathname = package_dir + "/" + _filename;
   string pathname = package_dir + "/" + _filename;
   struct stat st;
   struct stat st;
   if (stat(pathname.c_str(), &st) != 0) {
   if (stat(pathname.c_str(), &st) != 0) {
-    cerr << "file not found: " << _filename << "\n";
+    nout << "file not found: " << _filename << "\n";
     return false;
     return false;
   }
   }
 
 
   if (st.st_size != _size) {
   if (st.st_size != _size) {
     // If the size is wrong, the file fails.
     // If the size is wrong, the file fails.
-    cerr << "size wrong: " << _filename << "\n";
+    nout << "size wrong: " << _filename << "\n";
     return false;
     return false;
   }
   }
 
 
@@ -809,11 +809,11 @@ full_verify(const string &package_dir) const {
   // soft-fails.  We follow this up with a hash check.
   // soft-fails.  We follow this up with a hash check.
   if (!check_hash(pathname)) {
   if (!check_hash(pathname)) {
     // Hard fail, the hash is wrong.
     // Hard fail, the hash is wrong.
-    cerr << "hash check wrong: " << _filename << "\n";
+    nout << "hash check wrong: " << _filename << "\n";
     return false;
     return false;
   }
   }
 
 
-  cerr << "hash check ok: " << _filename << "\n";
+  nout << "hash check ok: " << _filename << "\n";
 
 
   // The hash is OK.  If the timestamp is wrong, change it back to
   // The hash is OK.  If the timestamp is wrong, change it back to
   // what we expect it to be, so we can quick-verify it successfully
   // what we expect it to be, so we can quick-verify it successfully
@@ -839,7 +839,7 @@ bool P3DPackage::FileSpec::
 check_hash(const string &pathname) const {
 check_hash(const string &pathname) const {
   ifstream stream(pathname.c_str(), ios::in | ios::binary);
   ifstream stream(pathname.c_str(), ios::in | ios::binary);
   if (!stream) {
   if (!stream) {
-    cerr << "unable to read " << pathname << "\n";
+    nout << "unable to read " << pathname << "\n";
     return false;
     return false;
   }
   }
 
 

+ 3 - 3
direct/src/plugin/p3dProgressWindow.cxx

@@ -47,14 +47,14 @@ package_ready(P3DPackage *package, bool success) {
       if (success) {
       if (success) {
         _session->start_p3dpython();
         _session->start_p3dpython();
       } else {
       } else {
-        cerr << "Failed to install " << package->get_package_name()
+        nout << "Failed to install " << package->get_package_name()
              << "_" << package->get_package_version() << "\n";
              << "_" << package->get_package_version() << "\n";
       }
       }
     } else {
     } else {
-      cerr << "Unexpected panda3d package: " << package << "\n";
+      nout << "Unexpected panda3d package: " << package << "\n";
     }
     }
   } else {
   } else {
-    cerr << "Unexpected callback for P3DSession\n";
+    nout << "Unexpected callback for P3DSession\n";
   }
   }
 }
 }
 
 

+ 23 - 18
direct/src/plugin/p3dPythonRun.cxx

@@ -44,10 +44,10 @@ P3DPythonRun(int argc, char *argv[]) {
   HANDLE read = GetStdHandle(STD_INPUT_HANDLE);
   HANDLE read = GetStdHandle(STD_INPUT_HANDLE);
   HANDLE write = GetStdHandle(STD_OUTPUT_HANDLE);
   HANDLE write = GetStdHandle(STD_OUTPUT_HANDLE);
   if (!SetStdHandle(STD_INPUT_HANDLE, INVALID_HANDLE_VALUE)) {
   if (!SetStdHandle(STD_INPUT_HANDLE, INVALID_HANDLE_VALUE)) {
-    cerr << "unable to reset input handle\n";
+    nout << "unable to reset input handle\n";
   }
   }
   if (!SetStdHandle(STD_OUTPUT_HANDLE, INVALID_HANDLE_VALUE)) {
   if (!SetStdHandle(STD_OUTPUT_HANDLE, INVALID_HANDLE_VALUE)) {
-    cerr << "unable to reset input handle\n";
+    nout << "unable to reset input handle\n";
   }
   }
 
 
   _pipe_read.open_read(read);
   _pipe_read.open_read(read);
@@ -58,10 +58,10 @@ P3DPythonRun(int argc, char *argv[]) {
 #endif  // _WIN32
 #endif  // _WIN32
 
 
   if (!_pipe_read) {
   if (!_pipe_read) {
-    cerr << "unable to open read pipe\n";
+    nout << "unable to open read pipe\n";
   }
   }
   if (!_pipe_write) {
   if (!_pipe_write) {
-    cerr << "unable to open write pipe\n";
+    nout << "unable to open write pipe\n";
   }
   }
 
 
   spawn_read_thread();
   spawn_read_thread();
@@ -126,14 +126,14 @@ run_python() {
   task_mgr->add(_check_comm_task);
   task_mgr->add(_check_comm_task);
 
 
   // Finally, get lost in taskMgr.run().
   // Finally, get lost in taskMgr.run().
-  cerr << "calling run()\n";
+  nout << "calling run()\n";
   PyObject *done = PyObject_CallMethod(_taskMgr, "run", "");
   PyObject *done = PyObject_CallMethod(_taskMgr, "run", "");
   if (done == NULL) {
   if (done == NULL) {
     PyErr_Print();
     PyErr_Print();
     return false;
     return false;
   }
   }
   Py_DECREF(done);
   Py_DECREF(done);
-  cerr << "done calling run()\n";
+  nout << "done calling run()\n";
 
 
   return true;
   return true;
 }
 }
@@ -146,7 +146,7 @@ run_python() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void P3DPythonRun::
 void P3DPythonRun::
 handle_command(TiXmlDocument *doc) {
 handle_command(TiXmlDocument *doc) {
-  cerr << "got command: " << *doc << "\n";
+  nout << "got command: " << *doc << "\n";
   TiXmlElement *xcommand = doc->FirstChildElement("command");
   TiXmlElement *xcommand = doc->FirstChildElement("command");
   if (xcommand != NULL) {
   if (xcommand != NULL) {
     const char *cmd = xcommand->Attribute("cmd");
     const char *cmd = xcommand->Attribute("cmd");
@@ -166,7 +166,7 @@ handle_command(TiXmlDocument *doc) {
         terminate_session();
         terminate_session();
         
         
       } else {
       } else {
-        cerr << "Unhandled command " << cmd << "\n";
+        nout << "Unhandled command " << cmd << "\n";
       }
       }
     }
     }
   }
   }
@@ -254,7 +254,7 @@ spawn_read_thread() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void P3DPythonRun::
 void P3DPythonRun::
 join_read_thread() {
 join_read_thread() {
-  cerr << "waiting for thread\n";
+  nout << "waiting for thread\n";
   _read_thread_continue = false;
   _read_thread_continue = false;
   _pipe_read.close();
   _pipe_read.close();
   
   
@@ -267,7 +267,7 @@ join_read_thread() {
   void *return_val;
   void *return_val;
   pthread_join(_read_thread, &return_val);
   pthread_join(_read_thread, &return_val);
 #endif
 #endif
-  cerr << "done waiting for thread\n";
+  nout << "done waiting for thread\n";
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -278,7 +278,7 @@ join_read_thread() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void P3DPythonRun::
 void P3DPythonRun::
 start_instance(P3DCInstance *inst) {
 start_instance(P3DCInstance *inst) {
-  cerr << "starting instance " << inst->get_p3d_filename() << "\n";
+  nout << "starting instance " << inst->get_p3d_filename() << "\n";
   _instances[inst->get_instance_id()] = inst;
   _instances[inst->get_instance_id()] = inst;
 
 
   string window_type;
   string window_type;
@@ -312,8 +312,13 @@ start_instance(P3DCInstance *inst) {
     PyErr_Print();
     PyErr_Print();
   }
   }
   Py_XDECREF(result);
   Py_XDECREF(result);
+
+  PyObject *tokens = inst->get_py_tokens();
   
   
-  result = PyObject_CallFunction(_runPackedApp, "[s]", inst->get_p3d_filename().c_str());
+  result = PyObject_CallFunction
+    (_runPackedApp, "sO", inst->get_p3d_filename().c_str(), tokens);
+  Py_DECREF(tokens);
+
   if (result == NULL) {
   if (result == NULL) {
     PyErr_Print();
     PyErr_Print();
   }
   }
@@ -329,7 +334,7 @@ void P3DPythonRun::
 terminate_instance(int id) {
 terminate_instance(int id) {
   Instances::iterator ii = _instances.find(id);
   Instances::iterator ii = _instances.find(id);
   if (ii == _instances.end()) {
   if (ii == _instances.end()) {
-    cerr << "Can't stop instance " << id << ": not started.\n";
+    nout << "Can't stop instance " << id << ": not started.\n";
     return;
     return;
   }
   }
 
 
@@ -358,14 +363,14 @@ terminate_session() {
   }
   }
   _instances.clear();
   _instances.clear();
 
 
-  cerr << "calling stop()\n";
+  nout << "calling stop()\n";
   PyObject *result = PyObject_CallMethod(_taskMgr, "stop", "");
   PyObject *result = PyObject_CallMethod(_taskMgr, "stop", "");
   if (result == NULL) {
   if (result == NULL) {
     PyErr_Print();
     PyErr_Print();
     return;
     return;
   }
   }
   Py_DECREF(result);
   Py_DECREF(result);
-  cerr << "done calling stop()\n";
+  nout << "done calling stop()\n";
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -375,14 +380,14 @@ terminate_session() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void P3DPythonRun::
 void P3DPythonRun::
 rt_thread_run() {
 rt_thread_run() {
-  cerr << "thread reading.\n";
+  nout << "thread reading.\n";
   while (_read_thread_continue) {
   while (_read_thread_continue) {
     TiXmlDocument *doc = new TiXmlDocument;
     TiXmlDocument *doc = new TiXmlDocument;
 
 
     _pipe_read >> *doc;
     _pipe_read >> *doc;
     if (!_pipe_read || _pipe_read.eof()) {
     if (!_pipe_read || _pipe_read.eof()) {
       // Some error on reading.  Abort.
       // Some error on reading.  Abort.
-      cerr << "Error on reading.\n";
+      nout << "Error on reading.\n";
       _program_continue = false;
       _program_continue = false;
       return;
       return;
     }
     }
@@ -444,7 +449,7 @@ main(int argc, char *argv[]) {
   P3DPythonRun run(argc, argv);
   P3DPythonRun run(argc, argv);
   
   
   if (!run.run_python()) {
   if (!run.run_python()) {
-    cerr << "Couldn't initialize Python.\n";
+    nout << "Couldn't initialize Python.\n";
     return 1;
     return 1;
   }
   }
   return 0;
   return 0;

+ 3 - 3
direct/src/plugin/p3dSession.I

@@ -19,7 +19,7 @@
 //  Description: Returns a string that uniquely identifies this
 //  Description: Returns a string that uniquely identifies this
 //               session.  See P3dInstance::get_session_key().
 //               session.  See P3dInstance::get_session_key().
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-INLINE const string &P3DSession::
+inline const string &P3DSession::
 get_session_key() const {
 get_session_key() const {
   return _session_key;
   return _session_key;
 }
 }
@@ -30,7 +30,7 @@ get_session_key() const {
 //  Description: Returns a string that uniquely identifies this
 //  Description: Returns a string that uniquely identifies this
 //               session's required Python version.
 //               session's required Python version.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-INLINE const string &P3DSession::
+inline const string &P3DSession::
 get_python_version() const {
 get_python_version() const {
   return _python_version;
   return _python_version;
 }
 }
@@ -42,7 +42,7 @@ get_python_version() const {
 //               within the session.  When this is zero, the session
 //               within the session.  When this is zero, the session
 //               may be safely deleted.
 //               may be safely deleted.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-INLINE int P3DSession::
+inline int P3DSession::
 get_num_instances() const {
 get_num_instances() const {
   return _instances.size();
   return _instances.size();
 }
 }

+ 20 - 20
direct/src/plugin/p3dSession.cxx

@@ -89,7 +89,7 @@ P3DSession::
     // Now give the process a chance to terminate itself cleanly.
     // Now give the process a chance to terminate itself cleanly.
     if (WaitForSingleObject(_p3dpython_handle, 2000) == WAIT_TIMEOUT) {
     if (WaitForSingleObject(_p3dpython_handle, 2000) == WAIT_TIMEOUT) {
       // It didn't shut down cleanly, so kill it the hard way.
       // It didn't shut down cleanly, so kill it the hard way.
-      cerr << "Terminating process.\n";
+      nout << "Terminating process.\n";
       TerminateProcess(_p3dpython_handle, 2);
       TerminateProcess(_p3dpython_handle, 2);
     }
     }
 
 
@@ -232,8 +232,8 @@ send_command(TiXmlDocument *command) {
 void P3DSession::
 void P3DSession::
 start_p3dpython() {
 start_p3dpython() {
 #ifdef _WIN32
 #ifdef _WIN32
-  //string p3dpython = "c:/cygwin/home/drose/player/direct/built/bin/p3dpython.exe";
-  string p3dpython = _python_root_dir + "/p3dpython.exe";
+  string p3dpython = "c:/cygwin/home/drose/player/direct/built/bin/p3dpython.exe";
+  //string p3dpython = _python_root_dir + "/p3dpython.exe";
 #else
 #else
   string p3dpython = "/Users/drose/player/direct/built/bin/p3dpython";
   string p3dpython = "/Users/drose/player/direct/built/bin/p3dpython";
 #endif
 #endif
@@ -244,9 +244,9 @@ start_p3dpython() {
   // These are the enviroment variables we forward from the current
   // These are the enviroment variables we forward from the current
   // environment, if they are set.
   // environment, if they are set.
   const char *keep[] = {
   const char *keep[] = {
-    "TEMP", "HOME", "USER", 
+    "TMP", "TEMP", "HOME", "USER", 
 #ifdef _WIN32
 #ifdef _WIN32
-    "SYSTEMROOT",
+    "SYSTEMROOT", "USERPROFILE",
 #endif
 #endif
     NULL
     NULL
   };
   };
@@ -290,18 +290,18 @@ start_p3dpython() {
 #endif
 #endif
 
 
   if (!started_p3dpython) {
   if (!started_p3dpython) {
-    cerr << "Failed to create process.\n";
+    nout << "Failed to create process.\n";
     return;
     return;
   }
   }
   _p3dpython_running = true;
   _p3dpython_running = true;
 
 
-  cerr << "Created child process\n";
+  nout << "Created child process\n";
 
 
   if (!_pipe_read) {
   if (!_pipe_read) {
-    cerr << "unable to open read pipe\n";
+    nout << "unable to open read pipe\n";
   }
   }
   if (!_pipe_write) {
   if (!_pipe_write) {
-    cerr << "unable to open write pipe\n";
+    nout << "unable to open write pipe\n";
   }
   }
   
   
   spawn_read_thread();
   spawn_read_thread();
@@ -358,7 +358,7 @@ join_read_thread() {
     return;
     return;
   }
   }
 
 
-  cerr << "session waiting for thread\n";
+  nout << "session waiting for thread\n";
   _read_thread_continue = false;
   _read_thread_continue = false;
   _pipe_read.close();
   _pipe_read.close();
   
   
@@ -371,7 +371,7 @@ join_read_thread() {
   void *return_val;
   void *return_val;
   pthread_join(_read_thread, &return_val);
   pthread_join(_read_thread, &return_val);
 #endif
 #endif
-  cerr << "session done waiting for thread\n";
+  nout << "session done waiting for thread\n";
 
 
   _started_read_thread = false;
   _started_read_thread = false;
 }
 }
@@ -383,20 +383,20 @@ join_read_thread() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void P3DSession::
 void P3DSession::
 rt_thread_run() {
 rt_thread_run() {
-  cerr << "session thread reading.\n";
+  nout << "session thread reading.\n";
   while (_read_thread_continue) {
   while (_read_thread_continue) {
     TiXmlDocument *doc = new TiXmlDocument;
     TiXmlDocument *doc = new TiXmlDocument;
 
 
     _pipe_read >> *doc;
     _pipe_read >> *doc;
     if (!_pipe_read || _pipe_read.eof()) {
     if (!_pipe_read || _pipe_read.eof()) {
       // Some error on reading.  Abort.
       // Some error on reading.  Abort.
-      cerr << "Error on session reading.\n";
+      nout << "Error on session reading.\n";
       rt_terminate();
       rt_terminate();
       return;
       return;
     }
     }
 
 
     // Successfully read an XML document.
     // Successfully read an XML document.
-    cerr << "Session got request: " << *doc << "\n";
+    nout << "Session got request: " << *doc << "\n";
 
 
     // TODO: feed the request up to the parent.
     // TODO: feed the request up to the parent.
     delete doc;
     delete doc;
@@ -478,7 +478,7 @@ win_create_process(const string &program, const string &start_dir,
 
 
   // Create the pipe to the process.
   // Create the pipe to the process.
   if (!CreatePipe(&r_to, &w_to, NULL, 0)) {
   if (!CreatePipe(&r_to, &w_to, NULL, 0)) {
-    cerr << "failed to create pipe\n";
+    nout << "failed to create pipe\n";
   } else {
   } else {
     // Make sure the right end of the pipe is inheritable.
     // Make sure the right end of the pipe is inheritable.
     SetHandleInformation(r_to, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
     SetHandleInformation(r_to, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
@@ -487,7 +487,7 @@ win_create_process(const string &program, const string &start_dir,
 
 
   // Create the pipe from the process.
   // Create the pipe from the process.
   if (!CreatePipe(&r_from, &w_from, NULL, 0)) {
   if (!CreatePipe(&r_from, &w_from, NULL, 0)) {
-    cerr << "failed to create pipe\n";
+    nout << "failed to create pipe\n";
   } else { 
   } else { 
     // Make sure the right end of the pipe is inheritable.
     // Make sure the right end of the pipe is inheritable.
     SetHandleInformation(w_from, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
     SetHandleInformation(w_from, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
@@ -507,7 +507,7 @@ win_create_process(const string &program, const string &start_dir,
       error_handle = handle;
       error_handle = handle;
       SetHandleInformation(error_handle, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
       SetHandleInformation(error_handle, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
     } else {
     } else {
-      cerr << "Unable to open " << output_filename << "\n";
+      nout << "Unable to open " << output_filename << "\n";
     }
     }
   }
   }
 
 
@@ -606,7 +606,7 @@ posix_create_process(const string &program, const string &start_dir,
       int logfile_fd = open(output_filename.c_str(), 
       int logfile_fd = open(output_filename.c_str(), 
                             O_WRONLY | O_CREAT | O_TRUNC, 0666);
                             O_WRONLY | O_CREAT | O_TRUNC, 0666);
       if (logfile_fd < 0) {
       if (logfile_fd < 0) {
-        cerr << "Unable to open " << output_filename << "\n";
+        nout << "Unable to open " << output_filename << "\n";
       } else {
       } else {
         dup2(logfile_fd, STDERR_FILENO);
         dup2(logfile_fd, STDERR_FILENO);
         close(logfile_fd);
         close(logfile_fd);
@@ -621,7 +621,7 @@ posix_create_process(const string &program, const string &start_dir,
     close(from_fd[0]);
     close(from_fd[0]);
 
 
     if (chdir(start_dir.c_str()) < 0) {
     if (chdir(start_dir.c_str()) < 0) {
-      cerr << "Could not chdir to " << start_dir << "\n";
+      nout << "Could not chdir to " << start_dir << "\n";
       _exit(1);
       _exit(1);
     }
     }
 
 
@@ -637,7 +637,7 @@ posix_create_process(const string &program, const string &start_dir,
     ptrs.push_back((char *)NULL);
     ptrs.push_back((char *)NULL);
     
     
     execle(program.c_str(), program.c_str(), (char *)0, &ptrs[0]);
     execle(program.c_str(), program.c_str(), (char *)0, &ptrs[0]);
-    cerr << "Failed to exec " << program << "\n";
+    nout << "Failed to exec " << program << "\n";
     _exit(1);
     _exit(1);
   }
   }
 
 

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

@@ -38,13 +38,13 @@ public:
   P3DSession(P3DInstance *inst);
   P3DSession(P3DInstance *inst);
   ~P3DSession();
   ~P3DSession();
 
 
-  INLINE const string &get_session_key() const;
-  INLINE const string &get_python_version() const;
+  inline const string &get_session_key() const;
+  inline const string &get_python_version() const;
 
 
   void start_instance(P3DInstance *inst);
   void start_instance(P3DInstance *inst);
   void terminate_instance(P3DInstance *inst);
   void terminate_instance(P3DInstance *inst);
 
 
-  INLINE int get_num_instances() const;
+  inline int get_num_instances() const;
 
 
 private:
 private:
   void send_command(TiXmlDocument *command);
   void send_command(TiXmlDocument *command);

+ 4 - 4
direct/src/plugin/p3dWinProgressWindow.cxx

@@ -118,7 +118,7 @@ thread_run() {
   retval = GetMessage(&msg, NULL, 0, 0);
   retval = GetMessage(&msg, NULL, 0, 0);
   while (retval != 0 && _thread_continue) {
   while (retval != 0 && _thread_continue) {
     if (retval == -1) {
     if (retval == -1) {
-      cerr << "Error processing message queue.\n";
+      nout << "Error processing message queue.\n";
       break;
       break;
     }
     }
     TranslateMessage(&msg);
     TranslateMessage(&msg);
@@ -186,7 +186,7 @@ make_window() {
     wc.lpszClassName = "panda3d_progress";
     wc.lpszClassName = "panda3d_progress";
     
     
     if (!RegisterClass(&wc)) {
     if (!RegisterClass(&wc)) {
-      cerr << "Could not register window class!\n";
+      nout << "Could not register window class!\n";
     }
     }
     registered_class = true;
     registered_class = true;
   }
   }
@@ -218,7 +218,7 @@ make_window() {
                    parent_hwnd, NULL, application, 0);
                    parent_hwnd, NULL, application, 0);
     
     
     if (!_hwnd) {
     if (!_hwnd) {
-      cerr << "Could not create embedded window!\n";
+      nout << "Could not create embedded window!\n";
       return;
       return;
     }
     }
 
 
@@ -234,7 +234,7 @@ make_window() {
                    x, y, width, height,
                    x, y, width, height,
                    NULL, NULL, application, 0);
                    NULL, NULL, application, 0);
     if (!_hwnd) {
     if (!_hwnd) {
-      cerr << "Could not create toplevel window!\n";
+      nout << "Could not create toplevel window!\n";
       return;
       return;
     }
     }
 
 

+ 22 - 1
direct/src/plugin/p3d_plugin.cxx

@@ -24,8 +24,13 @@
 bool initialized_lock = false;
 bool initialized_lock = false;
 LOCK _lock;
 LOCK _lock;
 
 
+ofstream log;
+string plugin_output_filename;
+ostream *nout_stream;
+
+
 bool 
 bool 
-P3D_initialize(int api_version) {
+P3D_initialize(int api_version, const char *output_filename) {
   if (api_version != P3D_API_VERSION) {
   if (api_version != P3D_API_VERSION) {
     // Can't accept an incompatible version.
     // Can't accept an incompatible version.
     return false;
     return false;
@@ -37,6 +42,18 @@ P3D_initialize(int api_version) {
   }
   }
   ACQUIRE_LOCK(_lock);
   ACQUIRE_LOCK(_lock);
 
 
+  plugin_output_filename = string();
+  if (output_filename != NULL) {
+    plugin_output_filename = output_filename;
+  }
+  nout_stream = &cerr;
+  if (!plugin_output_filename.empty()) {
+    log.open(plugin_output_filename.c_str(), ios::out | ios::trunc);
+    if (log) {
+      nout_stream = &log;
+    }
+  }
+
   P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
   P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
   bool result = inst_mgr->initialize();
   bool result = inst_mgr->initialize();
   RELEASE_LOCK(_lock);
   RELEASE_LOCK(_lock);
@@ -61,6 +78,10 @@ P3D_create_instance(P3D_request_ready_func *func,
   assert(P3DInstanceManager::get_global_ptr()->is_initialized());
   assert(P3DInstanceManager::get_global_ptr()->is_initialized());
   ACQUIRE_LOCK(_lock);
   ACQUIRE_LOCK(_lock);
   P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
   P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
+  if (p3d_filename == NULL) {
+    p3d_filename = "";
+  }
+
   P3DInstance *result = 
   P3DInstance *result = 
     inst_mgr->create_instance(func, p3d_filename, window_type, 
     inst_mgr->create_instance(func, p3d_filename, window_type, 
                               win_x, win_y, win_width, win_height,
                               win_x, win_y, win_width, win_height,

+ 23 - 11
direct/src/plugin/p3d_plugin.h

@@ -73,7 +73,7 @@ extern "C" {
 libraries match.  It should be passed to P3D_initialize() (below).
 libraries match.  It should be passed to P3D_initialize() (below).
 This number will be incremented whenever there are changes to any of
 This number will be incremented whenever there are changes to any of
 the interface specifications defined in this header file. */
 the interface specifications defined in this header file. */
-#define P3D_API_VERSION 1
+#define P3D_API_VERSION 2
 
 
 /************************ GLOBAL FUNCTIONS **************************/
 /************************ GLOBAL FUNCTIONS **************************/
 
 
@@ -85,12 +85,17 @@ the interface specifications defined in this header file. */
    the dll can verify that it has been built with the same version of
    the dll can verify that it has been built with the same version of
    the API as the host.
    the API as the host.
 
 
+   The output_filename is usually NULL, but if you put a filename
+   here, it will be used as the log file for the output from the
+   plugin.  This is useful for debugging, particularly when running
+   within a browser that squelches stderr.
+
    This function returns true if the plugin is valid and uses a
    This function returns true if the plugin is valid and uses a
    compatible API, false otherwise.  If it returns false, the host
    compatible API, false otherwise.  If it returns false, the host
    should not call any more functions in this API, and should
    should not call any more functions in this API, and should
    immediately unload the DLL and (if possible) download a new one. */
    immediately unload the DLL and (if possible) download a new one. */
 typedef bool 
 typedef bool 
-P3D_initialize_func(int api_version);
+P3D_initialize_func(int api_version, const char *output_filename);
 
 
 /* This function frees a pointer returned by
 /* This function frees a pointer returned by
    P3D_instance_get_property(), or another similar function that
    P3D_instance_get_property(), or another similar function that
@@ -187,19 +192,26 @@ typedef struct {
   const char *_value;
   const char *_value;
 } P3D_token;
 } P3D_token;
 
 
-/* This function creates a new Panda3D instance.  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.  For tokens,
-   pass an array of P3D_token elements (above), which correspond to
-   the user-supplied keyword/value pairs that may appear in the embed
-   token within the HTML syntax; the host is responsible for
-   allocating this array, and for deallocating it after this call (the
-   plugin will make its own copy of the array).
+/* This function creates a new Panda3D instance.  
+
+   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.
+
+   For tokens, pass an array of P3D_token elements (above), which
+   correspond to the user-supplied keyword/value pairs that may appear
+   in the embed token within the HTML syntax; the host is responsible
+   for allocating this array, and for deallocating it after this call
+   (the plugin will make its own copy of the array).
 
 
    Most tokens are implemented by the application and are undefined at
    Most tokens are implemented by the application and are undefined at
-   the system level.  However, one token in particular is
+   the system level.  However, two tokens in particular are
    system-defined:
    system-defined:
 
 
+     "src" : names a URL that will be loaded for the contents of the
+       p3d file, if p3d_filename is empty or NULL.
+
      "output_filename" : names a file to create on disk which contains
      "output_filename" : names a file to create on disk which contains
        the console output from the application.  This may be useful in
        the console output from the application.  This may be useful in
        debugging.  If this is omitted, or an empty string, the console
        debugging.  If this is omitted, or an empty string, the console

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

@@ -26,12 +26,17 @@
 #include "p3d_lock.h"
 #include "p3d_lock.h"
 
 
 #include <iostream>
 #include <iostream>
+#include <fstream>
 #include <string>
 #include <string>
 #include <assert.h>
 #include <assert.h>
 
 
 using namespace std;
 using namespace std;
 
 
-#define INLINE inline
+// Appears in p3d_plugin.cxx.
+extern ofstream log;
+extern string plugin_output_filename;
+extern ostream *nout_stream;
+#define nout (*nout_stream)
 
 
 #endif
 #endif
 
 

+ 30 - 0
direct/src/plugin_npapi/Sources.pp

@@ -0,0 +1,30 @@
+// This directory is still experimental.  Define HAVE_P3D_PLUGIN in
+// your Config.pp to build it.
+#define BUILD_DIRECTORY $[and $[HAVE_P3D_PLUGIN],$[HAVE_NPAPI]]
+
+#define USE_PACKAGES npapi
+
+#begin lib_target
+  // By Mozilla convention, on Windows at least, the generated DLL
+  // filename must begin with "np", not "libnp".
+  #define TARGET nppanda3d
+  #define LIB_PREFIX
+
+  #define COMBINED_SOURCES \
+    $[TARGET]_composite1.cxx
+
+  #define SOURCES \
+    nppanda3d_common.h \
+    nppanda3d_startup.h \
+    ppInstance.h ppInstance.I
+
+  #define INCLUDED_SOURCES \
+    nppanda3d_startup.cxx \
+    ppInstance.cxx
+ 
+  #define WIN_RESOURCE_FILE nppanda3d.rc
+  #define LINKER_DEF_FILE nppanda3d.def
+
+  #define INSTALL_HEADERS
+
+#end lib_target

+ 320 - 0
direct/src/plugin_npapi/np_entry.cpp

@@ -0,0 +1,320 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: NPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Netscape Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/NPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is 
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or 
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the NPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the NPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+//////////////////////////////////////////////////////////////
+//
+// Main plugin entry point implementation -- exports from the 
+// plugin library
+//
+#include "npplat.h"
+#include "pluginbase.h"
+
+NPNetscapeFuncs NPNFuncs;
+
+NPError OSCALL NP_Shutdown()
+{
+  NS_PluginShutdown();
+  return NPERR_NO_ERROR;
+}
+
+static NPError fillPluginFunctionTable(NPPluginFuncs* aNPPFuncs)
+{
+  if(aNPPFuncs == NULL)
+    return NPERR_INVALID_FUNCTABLE_ERROR;
+
+  // Set up the plugin function table that Netscape will use to
+  // call us. Netscape needs to know about our version and size   
+  // and have a UniversalProcPointer for every function we implement.
+
+  aNPPFuncs->version       = (NP_VERSION_MAJOR << 8) | NP_VERSION_MINOR;
+#ifdef XP_MAC
+  aNPPFuncs->newp          = NewNPP_NewProc(Private_New);
+  aNPPFuncs->destroy       = NewNPP_DestroyProc(Private_Destroy);
+  aNPPFuncs->setwindow     = NewNPP_SetWindowProc(Private_SetWindow);
+  aNPPFuncs->newstream     = NewNPP_NewStreamProc(Private_NewStream);
+  aNPPFuncs->destroystream = NewNPP_DestroyStreamProc(Private_DestroyStream);
+  aNPPFuncs->asfile        = NewNPP_StreamAsFileProc(Private_StreamAsFile);
+  aNPPFuncs->writeready    = NewNPP_WriteReadyProc(Private_WriteReady);
+  aNPPFuncs->write         = NewNPP_WriteProc(Private_Write);
+  aNPPFuncs->print         = NewNPP_PrintProc(Private_Print);
+  aNPPFuncs->event         = NewNPP_HandleEventProc(Private_HandleEvent);	
+  aNPPFuncs->urlnotify     = NewNPP_URLNotifyProc(Private_URLNotify);			
+  aNPPFuncs->getvalue      = NewNPP_GetValueProc(Private_GetValue);
+  aNPPFuncs->setvalue      = NewNPP_SetValueProc(Private_SetValue);
+#else
+  aNPPFuncs->newp          = NPP_New;
+  aNPPFuncs->destroy       = NPP_Destroy;
+  aNPPFuncs->setwindow     = NPP_SetWindow;
+  aNPPFuncs->newstream     = NPP_NewStream;
+  aNPPFuncs->destroystream = NPP_DestroyStream;
+  aNPPFuncs->asfile        = NPP_StreamAsFile;
+  aNPPFuncs->writeready    = NPP_WriteReady;
+  aNPPFuncs->write         = NPP_Write;
+  aNPPFuncs->print         = NPP_Print;
+  aNPPFuncs->event         = NPP_HandleEvent;
+  aNPPFuncs->urlnotify     = NPP_URLNotify;
+  aNPPFuncs->getvalue      = NPP_GetValue;
+  aNPPFuncs->setvalue      = NPP_SetValue;
+#endif
+#ifdef OJI
+  aNPPFuncs->javaClass     = NULL;
+#endif
+
+  return NPERR_NO_ERROR;
+}
+
+static NPError fillNetscapeFunctionTable(NPNetscapeFuncs* aNPNFuncs)
+{
+  if(aNPNFuncs == NULL)
+    return NPERR_INVALID_FUNCTABLE_ERROR;
+
+  if(HIBYTE(aNPNFuncs->version) > NP_VERSION_MAJOR)
+    return NPERR_INCOMPATIBLE_VERSION_ERROR;
+
+  if(aNPNFuncs->size < sizeof(NPNetscapeFuncs))
+    return NPERR_INVALID_FUNCTABLE_ERROR;
+
+  NPNFuncs.size             = aNPNFuncs->size;
+  NPNFuncs.version          = aNPNFuncs->version;
+  NPNFuncs.geturlnotify     = aNPNFuncs->geturlnotify;
+  NPNFuncs.geturl           = aNPNFuncs->geturl;
+  NPNFuncs.posturlnotify    = aNPNFuncs->posturlnotify;
+  NPNFuncs.posturl          = aNPNFuncs->posturl;
+  NPNFuncs.requestread      = aNPNFuncs->requestread;
+  NPNFuncs.newstream        = aNPNFuncs->newstream;
+  NPNFuncs.write            = aNPNFuncs->write;
+  NPNFuncs.destroystream    = aNPNFuncs->destroystream;
+  NPNFuncs.status           = aNPNFuncs->status;
+  NPNFuncs.uagent           = aNPNFuncs->uagent;
+  NPNFuncs.memalloc         = aNPNFuncs->memalloc;
+  NPNFuncs.memfree          = aNPNFuncs->memfree;
+  NPNFuncs.memflush         = aNPNFuncs->memflush;
+  NPNFuncs.reloadplugins    = aNPNFuncs->reloadplugins;
+#ifdef OJI
+  NPNFuncs.getJavaEnv       = aNPNFuncs->getJavaEnv;
+  NPNFuncs.getJavaPeer      = aNPNFuncs->getJavaPeer;
+#endif
+  NPNFuncs.getvalue         = aNPNFuncs->getvalue;
+  NPNFuncs.setvalue         = aNPNFuncs->setvalue;
+  NPNFuncs.invalidaterect   = aNPNFuncs->invalidaterect;
+  NPNFuncs.invalidateregion = aNPNFuncs->invalidateregion;
+  NPNFuncs.forceredraw      = aNPNFuncs->forceredraw;
+
+  return NPERR_NO_ERROR;
+}
+
+//
+// Some exports are different on different platforms
+//
+
+/**************************************************/
+/*                                                */
+/*                   Windows                      */
+/*                                                */
+/**************************************************/
+#ifdef XP_WIN
+
+NPError OSCALL NP_Initialize(NPNetscapeFuncs* aNPNFuncs)
+{
+  NPError rv = fillNetscapeFunctionTable(aNPNFuncs);
+  if(rv != NPERR_NO_ERROR)
+    return rv;
+
+  return NS_PluginInitialize();
+}
+
+NPError OSCALL NP_GetEntryPoints(NPPluginFuncs* aNPPFuncs)
+{
+  return fillPluginFunctionTable(aNPPFuncs);
+}
+
+#endif //XP_WIN
+
+/**************************************************/
+/*                                                */
+/*                    Unix                        */
+/*                                                */
+/**************************************************/
+#ifdef XP_UNIX
+
+NPError NP_Initialize(NPNetscapeFuncs* aNPNFuncs, NPPluginFuncs* aNPPFuncs)
+{
+  NPError rv = fillNetscapeFunctionTable(aNPNFuncs);
+  if(rv != NPERR_NO_ERROR)
+    return rv;
+
+  rv = fillPluginFunctionTable(aNPPFuncs);
+  if(rv != NPERR_NO_ERROR)
+    return rv;
+
+  return NS_PluginInitialize();
+}
+
+char * NP_GetMIMEDescription(void)
+{
+  return NPP_GetMIMEDescription();
+}
+
+NPError NP_GetValue(void *future, NPPVariable aVariable, void *aValue)
+{
+  return NS_PluginGetValue(aVariable, aValue);
+}
+
+#endif //XP_UNIX
+
+/**************************************************/
+/*                                                */
+/*                     Mac                        */
+/*                                                */
+/**************************************************/
+#ifdef XP_MAC
+
+#if !TARGET_API_MAC_CARBON
+QDGlobals* gQDPtr; // Pointer to Netscape's QuickDraw globals
+#endif
+
+short gResFile; // Refnum of the plugin's resource file
+
+NPError Private_Initialize(void)
+{
+  NPError rv = NS_PluginInitialize();
+  return rv;
+}
+
+void Private_Shutdown(void)
+{
+  NS_PluginShutdown();
+  __destroy_global_chain();
+}
+
+void SetUpQD(void);
+
+void SetUpQD(void)
+{
+  ProcessSerialNumber PSN;
+  FSSpec              myFSSpec;
+  Str63               name;
+  ProcessInfoRec      infoRec;
+  OSErr               result = noErr;
+  CFragConnectionID   connID;
+  Str255              errName;
+
+  // Memorize the plugin¹s resource file refnum for later use.
+  gResFile = CurResFile();
+
+#if !TARGET_API_MAC_CARBON
+  // Ask the system if CFM is available.
+  long response;
+  OSErr err = Gestalt(gestaltCFMAttr, &response);
+  Boolean hasCFM = BitTst(&response, 31-gestaltCFMPresent);
+
+  if (hasCFM) {
+    // GetProcessInformation takes a process serial number and 
+    // will give us back the name and FSSpec of the application.
+    // See the Process Manager in IM.
+    infoRec.processInfoLength = sizeof(ProcessInfoRec);
+    infoRec.processName = name;
+    infoRec.processAppSpec = &myFSSpec;
+
+    PSN.highLongOfPSN = 0;
+    PSN.lowLongOfPSN = kCurrentProcess;
+
+    result = GetProcessInformation(&PSN, &infoRec);
+  }
+	else
+    // If no CFM installed, assume it must be a 68K app.
+    result = -1;		
+
+  if (result == noErr) {
+    // Now that we know the app name and FSSpec, we can call GetDiskFragment
+    // to get a connID to use in a subsequent call to FindSymbol (it will also
+    // return the address of ³main² in app, which we ignore).  If GetDiskFragment 
+    // returns an error, we assume the app must be 68K.
+    Ptr mainAddr; 	
+    result =  GetDiskFragment(infoRec.processAppSpec, 0L, 0L, infoRec.processName,
+                              kReferenceCFrag, &connID, (Ptr*)&mainAddr, errName);
+  }
+
+  if (result == noErr) {
+    // The app is a PPC code fragment, so call FindSymbol
+    // to get the exported ³qd² symbol so we can access its
+    // QuickDraw globals.
+    CFragSymbolClass symClass;
+    result = FindSymbol(connID, "\pqd", (Ptr*)&gQDPtr, &symClass);
+  }
+  else {
+    // The app is 68K, so use its A5 to compute the address
+    // of its QuickDraw globals.
+    gQDPtr = (QDGlobals*)(*((long*)SetCurrentA5()) - (sizeof(QDGlobals) - sizeof(GrafPtr)));
+  }
+#endif /* !TARGET_API_MAC_CARBON */
+}
+
+NPError main(NPNetscapeFuncs* nsTable, NPPluginFuncs* pluginFuncs, NPP_ShutdownUPP* unloadUpp);
+
+#if !TARGET_API_MAC_CARBON
+#pragma export on
+#if GENERATINGCFM
+RoutineDescriptor mainRD = BUILD_ROUTINE_DESCRIPTOR(uppNPP_MainEntryProcInfo, main);
+#endif
+#pragma export off
+#endif /* !TARGET_API_MAC_CARBON */
+
+
+NPError main(NPNetscapeFuncs* aNPNFuncs, NPPluginFuncs* aNPPFuncs, NPP_ShutdownUPP* aUnloadUpp)
+{
+  NPError rv = NPERR_NO_ERROR;
+
+  if (aUnloadUpp == NULL)
+    rv = NPERR_INVALID_FUNCTABLE_ERROR;
+
+  if (rv == NPERR_NO_ERROR)
+    rv = fillNetscapeFunctionTable(aNPNFuncs);
+
+  if (rv == NPERR_NO_ERROR) {
+    // defer static constructors until the global functions are initialized.
+    __InitCode__();
+    rv = fillPluginFunctionTable(aNPPFuncs);
+  }
+
+  *aUnloadUpp = NewNPP_ShutdownProc(Private_Shutdown);
+  SetUpQD();
+  rv = Private_Initialize();
+	
+  return rv;
+}
+#endif //XP_MAC

+ 215 - 0
direct/src/plugin_npapi/npn_gate.cpp

@@ -0,0 +1,215 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: NPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Netscape Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/NPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is 
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or 
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the NPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the NPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+
+////////////////////////////////////////////////////////////
+//
+// Implementation of Netscape entry points (NPN_*)
+//
+#include "npplat.h"
+
+extern NPNetscapeFuncs NPNFuncs;
+
+void NPN_Version(int* plugin_major, int* plugin_minor, int* netscape_major, int* netscape_minor)
+{
+  *plugin_major   = NP_VERSION_MAJOR;
+  *plugin_minor   = NP_VERSION_MINOR;
+  *netscape_major = HIBYTE(NPNFuncs.version);
+  *netscape_minor = LOBYTE(NPNFuncs.version);
+}
+
+NPError NPN_GetURLNotify(NPP instance, const char *url, const char *target, void* notifyData)
+{
+	int navMinorVers = NPNFuncs.version & 0xFF;
+  NPError rv = NPERR_NO_ERROR;
+
+  if( navMinorVers >= NPVERS_HAS_NOTIFICATION )
+		rv = CallNPN_GetURLNotifyProc(NPNFuncs.geturlnotify, instance, url, target, notifyData);
+	else
+		rv = NPERR_INCOMPATIBLE_VERSION_ERROR;
+
+  return rv;
+}
+
+NPError NPN_GetURL(NPP instance, const char *url, const char *target)
+{
+  NPError rv = CallNPN_GetURLProc(NPNFuncs.geturl, instance, url, target);
+  return rv;
+}
+
+NPError NPN_PostURLNotify(NPP instance, const char* url, const char* window, uint32 len, const char* buf, NPBool file, void* notifyData)
+{
+	int navMinorVers = NPNFuncs.version & 0xFF;
+  NPError rv = NPERR_NO_ERROR;
+
+	if( navMinorVers >= NPVERS_HAS_NOTIFICATION )
+		rv = CallNPN_PostURLNotifyProc(NPNFuncs.posturlnotify, instance, url, window, len, buf, file, notifyData);
+	else
+		rv = NPERR_INCOMPATIBLE_VERSION_ERROR;
+
+  return rv;
+}
+
+NPError NPN_PostURL(NPP instance, const char* url, const char* window, uint32 len, const char* buf, NPBool file)
+{
+  NPError rv = CallNPN_PostURLProc(NPNFuncs.posturl, instance, url, window, len, buf, file);
+  return rv;
+} 
+
+NPError NPN_RequestRead(NPStream* stream, NPByteRange* rangeList)
+{
+  NPError rv = CallNPN_RequestReadProc(NPNFuncs.requestread, stream, rangeList);
+  return rv;
+}
+
+NPError NPN_NewStream(NPP instance, NPMIMEType type, const char* target, NPStream** stream)
+{
+	int navMinorVersion = NPNFuncs.version & 0xFF;
+
+  NPError rv = NPERR_NO_ERROR;
+
+	if( navMinorVersion >= NPVERS_HAS_STREAMOUTPUT )
+		rv = CallNPN_NewStreamProc(NPNFuncs.newstream, instance, type, target, stream);
+	else
+		rv = NPERR_INCOMPATIBLE_VERSION_ERROR;
+
+  return rv;
+}
+
+int32 NPN_Write(NPP instance, NPStream *stream, int32 len, void *buffer)
+{
+	int navMinorVersion = NPNFuncs.version & 0xFF;
+  int32 rv = 0;
+
+  if( navMinorVersion >= NPVERS_HAS_STREAMOUTPUT )
+		rv = CallNPN_WriteProc(NPNFuncs.write, instance, stream, len, buffer);
+	else
+		rv = -1;
+
+  return rv;
+}
+
+NPError NPN_DestroyStream(NPP instance, NPStream* stream, NPError reason)
+{
+	int navMinorVersion = NPNFuncs.version & 0xFF;
+  NPError rv = NPERR_NO_ERROR;
+
+  if( navMinorVersion >= NPVERS_HAS_STREAMOUTPUT )
+		rv = CallNPN_DestroyStreamProc(NPNFuncs.destroystream, instance, stream, reason);
+	else
+		rv = NPERR_INCOMPATIBLE_VERSION_ERROR;
+
+  return rv;
+}
+
+void NPN_Status(NPP instance, const char *message)
+{
+  CallNPN_StatusProc(NPNFuncs.status, instance, message);
+}
+
+const char* NPN_UserAgent(NPP instance)
+{
+  const char * rv = NULL;
+  rv = CallNPN_UserAgentProc(NPNFuncs.uagent, instance);
+  return rv;
+}
+
+void* NPN_MemAlloc(uint32 size)
+{
+  void * rv = NULL;
+  rv = CallNPN_MemAllocProc(NPNFuncs.memalloc, size);
+  return rv;
+}
+
+void NPN_MemFree(void* ptr)
+{
+  CallNPN_MemFreeProc(NPNFuncs.memfree, ptr);
+}
+
+uint32 NPN_MemFlush(uint32 size)
+{
+  uint32 rv = CallNPN_MemFlushProc(NPNFuncs.memflush, size);
+  return rv;
+}
+
+void NPN_ReloadPlugins(NPBool reloadPages)
+{
+  CallNPN_ReloadPluginsProc(NPNFuncs.reloadplugins, reloadPages);
+}
+
+#ifdef OJI
+JRIEnv* NPN_GetJavaEnv(void)
+{
+  JRIEnv * rv = NULL;
+	rv = CallNPN_GetJavaEnvProc(NPNFuncs.getJavaEnv);
+  return rv;
+}
+
+jref NPN_GetJavaPeer(NPP instance)
+{
+  jref rv;
+  rv = CallNPN_GetJavaPeerProc(NPNFuncs.getJavaPeer, instance);
+  return rv;
+}
+#endif
+
+NPError NPN_GetValue(NPP instance, NPNVariable variable, void *value)
+{
+  NPError rv = CallNPN_GetValueProc(NPNFuncs.getvalue, instance, variable, value);
+  return rv;
+}
+
+NPError NPN_SetValue(NPP instance, NPPVariable variable, void *value)
+{
+  NPError rv = CallNPN_SetValueProc(NPNFuncs.setvalue, instance, variable, value);
+  return rv;
+}
+
+void NPN_InvalidateRect(NPP instance, NPRect *invalidRect)
+{
+  CallNPN_InvalidateRectProc(NPNFuncs.invalidaterect, instance, invalidRect);
+}
+
+void NPN_InvalidateRegion(NPP instance, NPRegion invalidRegion)
+{
+  CallNPN_InvalidateRegionProc(NPNFuncs.invalidateregion, instance, invalidRegion);
+}
+
+void NPN_ForceRedraw(NPP instance)
+{
+  CallNPN_ForceRedrawProc(NPNFuncs.forceredraw, instance);
+}

+ 358 - 0
direct/src/plugin_npapi/npp_gate.cpp

@@ -0,0 +1,358 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: NPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Netscape Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/NPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is 
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or 
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the NPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the NPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+
+////////////////////////////////////////////////////////////
+//
+// Implementation of plugin entry points (NPP_*)
+//
+#include "pluginbase.h"
+
+// here the plugin creates a plugin instance object which 
+// will be associated with this newly created NPP instance and 
+// will do all the neccessary job
+NPError NPP_New(NPMIMEType pluginType, NPP instance, uint16 mode, int16 argc, char* argn[], char* argv[], NPSavedData* saved)
+{   
+  if(instance == NULL)
+    return NPERR_INVALID_INSTANCE_ERROR;
+
+  NPError rv = NPERR_NO_ERROR;
+
+  // create a new plugin instance object
+  // initialization will be done when the associated window is ready
+  nsPluginCreateData ds;
+  
+  ds.instance = instance;
+  ds.type     = pluginType; 
+  ds.mode     = mode; 
+  ds.argc     = argc; 
+  ds.argn     = argn; 
+  ds.argv     = argv; 
+  ds.saved    = saved;
+
+  nsPluginInstanceBase * plugin = NS_NewPluginInstance(&ds);
+  if(plugin == NULL)
+    return NPERR_OUT_OF_MEMORY_ERROR;
+
+  // associate the plugin instance object with NPP instance
+  instance->pdata = (void *)plugin;
+  return rv;
+}
+
+// here is the place to clean up and destroy the nsPluginInstance object
+NPError NPP_Destroy (NPP instance, NPSavedData** save)
+{
+  if(instance == NULL)
+    return NPERR_INVALID_INSTANCE_ERROR;
+
+  NPError rv = NPERR_NO_ERROR;
+
+  nsPluginInstanceBase * plugin = (nsPluginInstanceBase *)instance->pdata;
+  if(plugin != NULL) {
+    plugin->shut();
+    NS_DestroyPluginInstance(plugin);
+  }
+  return rv;
+}
+
+// during this call we know when the plugin window is ready or
+// is about to be destroyed so we can do some gui specific
+// initialization and shutdown
+NPError NPP_SetWindow (NPP instance, NPWindow* pNPWindow)
+{    
+  if(instance == NULL)
+    return NPERR_INVALID_INSTANCE_ERROR;
+
+  NPError rv = NPERR_NO_ERROR;
+
+  if(pNPWindow == NULL)
+    return NPERR_GENERIC_ERROR;
+
+  nsPluginInstanceBase * plugin = (nsPluginInstanceBase *)instance->pdata;
+
+  if(plugin == NULL) 
+    return NPERR_GENERIC_ERROR;
+
+  // window just created
+  if(!plugin->isInitialized() && (pNPWindow->window != NULL)) { 
+    if(!plugin->init(pNPWindow)) {
+      NS_DestroyPluginInstance(plugin);
+      return NPERR_MODULE_LOAD_FAILED_ERROR;
+    }
+  }
+
+  // window goes away
+  if((pNPWindow->window == NULL) && plugin->isInitialized())
+    return plugin->SetWindow(pNPWindow);
+
+  // window resized?
+  if(plugin->isInitialized() && (pNPWindow->window != NULL))
+    return plugin->SetWindow(pNPWindow);
+
+  // this should not happen, nothing to do
+  if((pNPWindow->window == NULL) && !plugin->isInitialized())
+    return plugin->SetWindow(pNPWindow);
+
+  return rv;
+}
+
+NPError NPP_NewStream(NPP instance, NPMIMEType type, NPStream* stream, NPBool seekable, uint16* stype)
+{
+  if(instance == NULL)
+    return NPERR_INVALID_INSTANCE_ERROR;
+
+  nsPluginInstanceBase * plugin = (nsPluginInstanceBase *)instance->pdata;
+  if(plugin == NULL) 
+    return NPERR_GENERIC_ERROR;
+
+  NPError rv = plugin->NewStream(type, stream, seekable, stype);
+  return rv;
+}
+
+int32 NPP_WriteReady (NPP instance, NPStream *stream)
+{
+  if(instance == NULL)
+    return 0x0fffffff;
+
+  nsPluginInstanceBase * plugin = (nsPluginInstanceBase *)instance->pdata;
+  if(plugin == NULL) 
+    return 0x0fffffff;
+
+  int32 rv = plugin->WriteReady(stream);
+  return rv;
+}
+
+int32 NPP_Write (NPP instance, NPStream *stream, int32 offset, int32 len, void *buffer)
+{   
+  if(instance == NULL)
+    return len;
+
+  nsPluginInstanceBase * plugin = (nsPluginInstanceBase *)instance->pdata;
+  if(plugin == NULL) 
+    return len;
+
+  int32 rv = plugin->Write(stream, offset, len, buffer);
+  return rv;
+}
+
+NPError NPP_DestroyStream (NPP instance, NPStream *stream, NPError reason)
+{
+  if(instance == NULL)
+    return NPERR_INVALID_INSTANCE_ERROR;
+
+  nsPluginInstanceBase * plugin = (nsPluginInstanceBase *)instance->pdata;
+  if(plugin == NULL) 
+    return NPERR_GENERIC_ERROR;
+
+  NPError rv = plugin->DestroyStream(stream, reason);
+  return rv;
+}
+
+void NPP_StreamAsFile (NPP instance, NPStream* stream, const char* fname)
+{
+  if(instance == NULL)
+    return;
+
+  nsPluginInstanceBase * plugin = (nsPluginInstanceBase *)instance->pdata;
+  if(plugin == NULL) 
+    return;
+
+  plugin->StreamAsFile(stream, fname);
+}
+
+void NPP_Print (NPP instance, NPPrint* printInfo)
+{
+  if(instance == NULL)
+    return;
+
+  nsPluginInstanceBase * plugin = (nsPluginInstanceBase *)instance->pdata;
+  if(plugin == NULL) 
+    return;
+
+  plugin->Print(printInfo);
+}
+
+void NPP_URLNotify(NPP instance, const char* url, NPReason reason, void* notifyData)
+{
+  if(instance == NULL)
+    return;
+
+  nsPluginInstanceBase * plugin = (nsPluginInstanceBase *)instance->pdata;
+  if(plugin == NULL) 
+    return;
+
+  plugin->URLNotify(url, reason, notifyData);
+}
+
+NPError	NPP_GetValue(NPP instance, NPPVariable variable, void *value)
+{
+  if(instance == NULL)
+    return NPERR_INVALID_INSTANCE_ERROR;
+
+  nsPluginInstanceBase * plugin = (nsPluginInstanceBase *)instance->pdata;
+  if(plugin == NULL) 
+    return NPERR_GENERIC_ERROR;
+
+  NPError rv = plugin->GetValue(variable, value);
+  return rv;
+}
+
+NPError NPP_SetValue(NPP instance, NPNVariable variable, void *value)
+{
+  if(instance == NULL)
+    return NPERR_INVALID_INSTANCE_ERROR;
+
+  nsPluginInstanceBase * plugin = (nsPluginInstanceBase *)instance->pdata;
+  if(plugin == NULL) 
+    return NPERR_GENERIC_ERROR;
+
+  NPError rv = plugin->SetValue(variable, value);
+  return rv;
+}
+
+int16	NPP_HandleEvent(NPP instance, void* event)
+{
+  if(instance == NULL)
+    return 0;
+
+  nsPluginInstanceBase * plugin = (nsPluginInstanceBase *)instance->pdata;
+  if(plugin == NULL) 
+    return 0;
+
+  uint16 rv = plugin->HandleEvent(event);
+  return rv;
+}
+
+#ifdef OJI
+jref NPP_GetJavaClass (void)
+{
+  return NULL;
+}
+#endif
+
+/**************************************************/
+/*                                                */
+/*                     Mac                        */
+/*                                                */
+/**************************************************/
+
+// Mac needs these wrappers, see npplat.h for more info
+
+#ifdef XP_MAC
+
+NPError	Private_New(NPMIMEType pluginType, NPP instance, uint16 mode, int16 argc, char* argn[], char* argv[], NPSavedData* saved)
+{
+  NPError rv = NPP_New(pluginType, instance, mode, argc, argn, argv, saved);
+  return rv;	
+}
+
+NPError Private_Destroy(NPP instance, NPSavedData** save)
+{
+  NPError rv = NPP_Destroy(instance, save);
+  return rv;
+}
+
+NPError Private_SetWindow(NPP instance, NPWindow* window)
+{
+  NPError rv = NPP_SetWindow(instance, window);
+  return rv;
+}
+
+NPError Private_NewStream(NPP instance, NPMIMEType type, NPStream* stream, NPBool seekable, uint16* stype)
+{
+  NPError rv = NPP_NewStream(instance, type, stream, seekable, stype);
+  return rv;
+}
+
+int32 Private_WriteReady(NPP instance, NPStream* stream)
+{
+  int32 rv = NPP_WriteReady(instance, stream);
+  return rv;
+}
+
+int32 Private_Write(NPP instance, NPStream* stream, int32 offset, int32 len, void* buffer)
+{
+  int32 rv = NPP_Write(instance, stream, offset, len, buffer);
+  return rv;
+}
+
+void Private_StreamAsFile(NPP instance, NPStream* stream, const char* fname)
+{
+  NPP_StreamAsFile(instance, stream, fname);
+}
+
+
+NPError Private_DestroyStream(NPP instance, NPStream* stream, NPError reason)
+{
+  NPError rv = NPP_DestroyStream(instance, stream, reason);
+  return rv;
+}
+
+int16 Private_HandleEvent(NPP instance, void* event)
+{
+  int16 rv = NPP_HandleEvent(instance, event);
+  return rv;
+}
+
+void Private_Print(NPP instance, NPPrint* platformPrint)
+{
+  NPP_Print(instance, platformPrint);
+}
+
+void Private_URLNotify(NPP instance, const char* url, NPReason reason, void* notifyData)
+{
+  NPP_URLNotify(instance, url, reason, notifyData);
+}
+
+jref Private_GetJavaClass(void)
+{
+  return NULL;
+}
+
+NPError Private_GetValue(NPP instance, NPPVariable variable, void *result)
+{
+  NPError rv = NPP_GetValue(instance, variable, result);
+  return rv;
+}
+
+NPError Private_SetValue(NPP instance, NPNVariable variable, void *value)
+{
+  NPError rv = NPP_SetValue(instance, variable, value);
+  return rv;
+}
+
+#endif //XP_MAC

+ 9 - 0
direct/src/plugin_npapi/nppanda3d.def

@@ -0,0 +1,9 @@
+; This file is required on Windows to export the appropriate symbols
+; from the DLL.
+
+LIBRARY   nppanda3d
+
+EXPORTS
+	NP_GetEntryPoints   @1
+	NP_Initialize       @2
+	NP_Shutdown         @3

+ 56 - 0
direct/src/plugin_npapi/nppanda3d.rc

@@ -0,0 +1,56 @@
+// This resource file is required on Windows to load the appropriate
+// text into the DLL, so Mozilla will recognize the DLL as a plugin.
+// It also defines the MIME type supported by the plugin.
+
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "winresrc.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 1,0,0,1
+ PRODUCTVERSION 1,0,0,1
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x40004L
+ FILETYPE 0x2L
+ FILESUBTYPE 0x0L
+BEGIN
+    BLOCK "StringFileInfo"
+    BEGIN
+        BLOCK "040904e4"
+        BEGIN
+            VALUE "Comments", "\0"
+            VALUE "CompanyName", " \0"
+            VALUE "FileDescription", "nppanda3d\0"
+            VALUE "FileExtents", "bic\0"
+            VALUE "FileOpenName", "nppanda3d\0"
+            VALUE "FileVersion", "1, 0, 0, 1\0"
+            VALUE "InternalName", "nppanda3d\0"
+            VALUE "LegalCopyright", "Copyright © 2001\0"
+            VALUE "LegalTrademarks", "\0"
+            VALUE "MIMEType", "application/x-panda3d\0"
+            VALUE "OriginalFilename", "nppanda3d.dll\0"
+            VALUE "PrivateBuild", "\0"
+            VALUE "ProductName", "Panda3D Example Plugin for Mozilla\0"
+            VALUE "ProductVersion", "1, 0, 0, 1\0"
+            VALUE "SpecialBuild", "\0"
+        END
+    END
+    BLOCK "VarFileInfo"
+    BEGIN
+        VALUE "Translation", 0x409, 1252
+    END
+END

+ 52 - 0
direct/src/plugin_npapi/nppanda3d_common.h

@@ -0,0 +1,52 @@
+// Filename: nppanda3d_common.h
+// Created by:  drose (19Jun09)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 NPPANDA3D_COMMON
+#define NPPANDA3D_COMMON
+
+// This header file is included by all C++ files in this directory
+
+// We include this header file directly out of its source directory,
+// so we don't have to link with the library that builds it.
+#include "../plugin/p3d_plugin.h"
+
+#include <iostream>
+#include <fstream>
+#include <string>
+#include <assert.h>
+
+using namespace std;
+
+// Appears in nppanda3d_startup.cxx.
+extern ofstream log;
+
+#ifdef _WIN32
+
+// Gecko requires all these symbols to be defined.
+#define MOZILLA_STRICT_API
+#define XP_WIN
+#define _X86_
+#define _WINDOWS
+#define _USRDLL
+#define NPBASIC_EXPORTS
+
+// Panda already defines this one.
+//#define WIN32
+
+#include <windows.h>
+
+#endif  // _WIN32
+
+#endif
+

+ 4 - 0
direct/src/plugin_npapi/nppanda3d_composite1.cxx

@@ -0,0 +1,4 @@
+#include "nppanda3d_startup.cxx"
+#include "ppInstance.cxx"
+
+

+ 65 - 0
direct/src/plugin_npapi/nppanda3d_startup.cxx

@@ -0,0 +1,65 @@
+// Filename: nppanda3d_startup.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 "nppanda3d_startup.h"
+#include "ppInstance.h"
+
+// These source files are part of the Gecko SDK, sort of.  They're
+// distributed with the sample applications.  They provide a
+// higher-level wrapper around some of the NPAPI startup stuff, and
+// this appears to be the intended way to use the Gecko SDK.  It's a
+// weird system.
+#include "npplat.h"
+#include "pluginbase.h"
+#include "np_entry.cpp"
+#include "npn_gate.cpp"
+#include "npp_gate.cpp"
+
+#include "../plugin/load_plugin_src.cxx"
+
+ofstream log;
+
+NPError
+NS_PluginInitialize() {
+  log.open("c:/cygwin/home/drose/t.log");
+  log << "initializing\n" << flush;
+
+  if (!load_plugin("")) {
+    log << "couldn't load plugin\n" << flush;
+    return NPERR_INVALID_PLUGIN_ERROR;
+  }
+
+  return NPERR_NO_ERROR;
+}
+
+void
+NS_PluginShutdown() {
+  log << "shutdown\n" << flush;
+#ifdef _WIN32
+  FreeLibrary(module);
+  module = NULL;
+#endif
+}
+
+nsPluginInstanceBase *
+NS_NewPluginInstance(nsPluginCreateData *create_data) {
+  log << "new instance\n" << flush;
+  return new PPInstance(create_data);
+}
+
+void
+NS_DestroyPluginInstance(nsPluginInstanceBase *plugin) {
+  log << "destroy instance\n" << flush;
+  delete (PPInstance *)plugin;
+}

+ 22 - 0
direct/src/plugin_npapi/nppanda3d_startup.h

@@ -0,0 +1,22 @@
+// Filename: nppanda3d_startup.h
+// Created by:  drose (19Jun09)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 NPPANDA3D_STARTUP_H
+#define NPPANDA3D_STARTUP_H
+
+#include "nppanda3d_common.h"
+
+#include "../plugin/load_plugin_src.h"
+
+#endif

+ 150 - 0
direct/src/plugin_npapi/npplat.h

@@ -0,0 +1,150 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: NPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Netscape Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/NPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is 
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or 
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the NPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the NPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef _NPPLAT_H_
+#define _NPPLAT_H_
+
+#include "npapi.h"
+#include "npupp.h"
+
+/**************************************************/
+/*                                                */
+/*                   Windows                      */
+/*                                                */
+/**************************************************/
+#ifdef XP_WIN
+#include "windows.h"
+#endif //XP_WIN
+
+/**************************************************/
+/*                                                */
+/*                    Unix                        */
+/*                                                */
+/**************************************************/
+#ifdef XP_UNIX
+#include <stdio.h>
+#endif //XP_UNIX
+
+/**************************************************/
+/*                                                */
+/*                     Mac                        */
+/*                                                */
+/**************************************************/
+#ifdef XP_MAC
+
+#include <Processes.h>
+#include <Gestalt.h>
+#include <CodeFragments.h>
+#include <Timer.h>
+#include <Resources.h>
+#include <ToolUtils.h>
+
+#include "jri.h"
+
+// The Mixed Mode procInfos defined in npupp.h assume Think C-
+// style calling conventions.  These conventions are used by
+// Metrowerks with the exception of pointer return types, which
+// in Metrowerks 68K are returned in A0, instead of the standard
+// D0. Thus, since NPN_MemAlloc and NPN_UserAgent return pointers,
+// Mixed Mode will return the values to a 68K plugin in D0, but 
+// a 68K plugin compiled by Metrowerks will expect the result in
+// A0.  The following pragma forces Metrowerks to use D0 instead.
+//
+#ifdef __MWERKS__
+#ifndef powerc
+#pragma pointers_in_D0
+#endif
+#endif
+
+#ifdef __MWERKS__
+#ifndef powerc
+#pragma pointers_in_A0
+#endif
+#endif
+
+// The following fix for static initializers (which fixes a preious
+// incompatibility with some parts of PowerPlant, was submitted by 
+// Jan Ulbrich.
+#ifdef __MWERKS__
+	#ifdef __cplusplus
+	extern "C" {
+	#endif
+		#ifndef powerc
+			extern void	__InitCode__(void);
+		#else
+			extern void __sinit(void);
+			#define __InitCode__ __sinit
+		#endif
+		extern void	__destroy_global_chain(void);
+	#ifdef __cplusplus
+	}
+	#endif // __cplusplus
+#endif // __MWERKS__
+
+// Wrapper functions for all calls from Netscape to the plugin.
+// These functions let the plugin developer just create the APIs
+// as documented and defined in npapi.h, without needing to 
+// install those functions in the function table or worry about
+// setting up globals for 68K plugins.
+NPError Private_Initialize(void);
+void    Private_Shutdown(void);
+NPError Private_New(NPMIMEType pluginType, NPP instance, uint16 mode, int16 argc, char* argn[], char* argv[], NPSavedData* saved);
+NPError Private_Destroy(NPP instance, NPSavedData** save);
+NPError Private_SetWindow(NPP instance, NPWindow* window);
+NPError Private_NewStream(NPP instance, NPMIMEType type, NPStream* stream, NPBool seekable, uint16* stype);
+NPError Private_DestroyStream(NPP instance, NPStream* stream, NPError reason);
+int32   Private_WriteReady(NPP instance, NPStream* stream);
+int32   Private_Write(NPP instance, NPStream* stream, int32 offset, int32 len, void* buffer);
+void    Private_StreamAsFile(NPP instance, NPStream* stream, const char* fname);
+void    Private_Print(NPP instance, NPPrint* platformPrint);
+int16   Private_HandleEvent(NPP instance, void* event);
+void    Private_URLNotify(NPP instance, const char* url, NPReason reason, void* notifyData);
+jref    Private_GetJavaClass(void);
+NPError Private_GetValue(NPP instance, NPPVariable variable, void *result);
+NPError Private_SetValue(NPP instance, NPNVariable variable, void *value);
+
+#endif //XP_MAC
+
+#ifndef HIBYTE
+#define HIBYTE(i) (i >> 8)
+#endif
+
+#ifndef LOBYTE
+#define LOBYTE(i) (i & 0xff)
+#endif
+
+#endif //_NPPLAT_H_

+ 96 - 0
direct/src/plugin_npapi/pluginbase.h

@@ -0,0 +1,96 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: NPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Netscape Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/NPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is 
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or 
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the NPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the NPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef __PLUGININSTANCEBASE_H__
+#define __PLUGININSTANCEBASE_H__
+
+#include "npplat.h"
+
+struct nsPluginCreateData
+{
+  NPP instance;
+  NPMIMEType type; 
+  uint16 mode; 
+  int16 argc; 
+  char** argn; 
+  char** argv; 
+  NPSavedData* saved;
+};
+
+class nsPluginInstanceBase
+{
+public:
+  // these three methods must be implemented in the derived
+  // class platform specific way
+  virtual NPBool init(NPWindow* aWindow) = 0;
+  virtual void shut() = 0;
+  virtual NPBool isInitialized() = 0;
+
+  // implement all or part of those methods in the derived 
+  // class as needed
+  virtual NPError SetWindow(NPWindow* pNPWindow)                    { return NPERR_NO_ERROR; }
+  virtual NPError NewStream(NPMIMEType type, NPStream* stream, 
+                            NPBool seekable, uint16* stype)         { return NPERR_NO_ERROR; }
+  virtual NPError DestroyStream(NPStream *stream, NPError reason)   { return NPERR_NO_ERROR; }
+  virtual void    StreamAsFile(NPStream* stream, const char* fname) { return; }
+  virtual int32   WriteReady(NPStream *stream)                      { return 0x0fffffff; }
+  virtual int32   Write(NPStream *stream, int32 offset, 
+                        int32 len, void *buffer)                    { return len; }
+  virtual void    Print(NPPrint* printInfo)                         { return; }
+  virtual uint16  HandleEvent(void* event)                          { return 0; }
+  virtual void    URLNotify(const char* url, NPReason reason, 
+                            void* notifyData)                       { return; }
+  virtual NPError GetValue(NPPVariable variable, void *value)       { return NPERR_NO_ERROR; }
+  virtual NPError SetValue(NPNVariable variable, void *value)       { return NPERR_NO_ERROR; }
+};
+
+// functions that should be implemented for each specific plugin
+
+// creation and destruction of the object of the derived class
+nsPluginInstanceBase * NS_NewPluginInstance(nsPluginCreateData * aCreateDataStruct);
+void NS_DestroyPluginInstance(nsPluginInstanceBase * aPlugin);
+
+// global plugin initialization and shutdown
+NPError NS_PluginInitialize();
+void NS_PluginShutdown();
+
+#ifdef XP_UNIX
+// global to get plugins name & description 
+NPError NS_PluginGetValue(NPPVariable aVariable, void *aValue);
+#endif
+
+#endif // __PLUGININSTANCEBASE_H__

+ 14 - 0
direct/src/plugin_npapi/ppInstance.I

@@ -0,0 +1,14 @@
+// Filename: ppInstance.I
+// Created by:  drose (19Jun09)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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."
+//
+////////////////////////////////////////////////////////////////////
+

+ 136 - 0
direct/src/plugin_npapi/ppInstance.cxx

@@ -0,0 +1,136 @@
+// Filename: ppInstance.cxx
+// Created by:  drose (19Jun09)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 "ppInstance.h"
+
+////////////////////////////////////////////////////////////////////
+//     Function: PPInstance::Constructor
+//       Access: Public
+//  Description: Creates a new instance of a Panda3D plugin window.
+//               The create_data structure is supplied from NPAPI, and
+//               defines the initial parameters specified in the HTML
+//               document.
+////////////////////////////////////////////////////////////////////
+PPInstance::
+PPInstance(nsPluginCreateData *create_data) {
+  log << "constructing " << this << "\n" << flush;
+  _inst = NULL;
+
+  log << "  instance = " << create_data->instance
+      << "\n  type = " << create_data->type
+      << "\n  mode = " << create_data->mode << "\n";
+
+  // Copy the tokens from the create_data structure.
+  _tokens.reserve(create_data->argc);
+  for (int i = 0; i < create_data->argc; ++i) {
+    P3D_token token;
+    token._keyword = strdup(create_data->argn[i]);
+    token._value = strdup(create_data->argv[i]);
+    log << " " << i << ": " << token._keyword << " = " << token._value << "\n";
+    _tokens.push_back(token);
+  }
+
+  _npp_mode = create_data->mode;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PPInstance::Destructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+PPInstance::
+~PPInstance() {
+  assert(_inst == NULL);
+  log << "destructing " << this << "\n" << flush;
+
+  Tokens::iterator ti;
+  for (ti = _tokens.begin(); ti != _tokens.end(); ++ti) {
+    free((char *)(*ti)._keyword);
+    free((char *)(*ti)._value);
+  }
+  _tokens.clear();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PPInstance::init
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+NPBool PPInstance::
+init(NPWindow *window) {
+  assert(_inst == NULL);
+  log << "init, window = " << window << "\n" << flush;
+  log << " x,y = " << window->x << "," << window->y
+      << " w,h = " << window->width << "," << window->height
+      << "\n" << flush;
+
+  P3D_window_handle parent_window;
+#ifdef _WIN32
+  parent_window._hwnd = (HWND)(window->window);
+#endif
+
+  P3D_window_type window_type = P3D_WT_embedded;
+
+  const P3D_token *tokens = NULL;
+  if (!_tokens.empty()) {
+    tokens = &_tokens[0];
+  }
+
+  _inst = P3D_create_instance
+    (NULL, NULL, window_type,
+     window->x, window->y, window->width, window->height,
+     parent_window, tokens, _tokens.size());
+
+  return (_inst != NULL);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PPInstance::shut
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void PPInstance::
+shut() {
+  assert(_inst != NULL);
+  log << "shut\n";
+  P3D_instance_finish(_inst);
+  _inst = NULL;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PPInstance::isInitialized
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+NPBool PPInstance::
+isInitialized() {
+  return _inst != NULL;
+}
+
+/*
+  virtual NPError SetWindow(NPWindow *pNPWindow);
+  virtual NPError NewStream(NPMIMEType type, NPStream *stream, 
+                            NPBool seekable, uint16 *stype);
+  virtual NPError DestroyStream(NPStream *stream, NPError reason);
+  virtual void    StreamAsFile(NPStream *stream, const char *fname);
+  virtual int32   WriteReady(NPStream *stream);
+  virtual int32   Write(NPStream *stream, int32 offset, 
+                        int32 len, void *buffer);
+  virtual void    Print(NPPrint *printInfo);
+  virtual uint16  HandleEvent(void *event);
+  virtual void    URLNotify(const char *url, NPReason reason, 
+                            void *notifyData);
+  virtual NPError GetValue(NPPVariable variable, void *value);
+  virtual NPError SetValue(NPNVariable variable, void *value);
+*/

+ 68 - 0
direct/src/plugin_npapi/ppInstance.h

@@ -0,0 +1,68 @@
+// Filename: ppInstance.h
+// Created by:  drose (19Jun09)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 PPINSTANCE_H
+#define PPINSTANCE_H
+
+#include "nppanda3d_common.h"
+#include "pluginbase.h"
+
+#include <vector>
+
+////////////////////////////////////////////////////////////////////
+//       Class : PPInstance
+// Description : This represents a single instance of the Panda3D
+//               plugin, via the NPAPI interface.  This instance
+//               brokers the communication with the P3D Core API, as
+//               defined in the plugin directory.
+////////////////////////////////////////////////////////////////////
+class PPInstance : public nsPluginInstanceBase {
+public:
+  PPInstance(nsPluginCreateData *create_data);
+  ~PPInstance();
+
+  // Methods inherited from base class
+
+  virtual NPBool init(NPWindow *aWindow);
+  virtual void shut();
+  virtual NPBool isInitialized();
+
+  /*
+  virtual NPError SetWindow(NPWindow *pNPWindow);
+  virtual NPError NewStream(NPMIMEType type, NPStream *stream, 
+                            NPBool seekable, uint16 *stype);
+  virtual NPError DestroyStream(NPStream *stream, NPError reason);
+  virtual void    StreamAsFile(NPStream *stream, const char *fname);
+  virtual int32   WriteReady(NPStream *stream);
+  virtual int32   Write(NPStream *stream, int32 offset, 
+                        int32 len, void *buffer);
+  virtual void    Print(NPPrint *printInfo);
+  virtual uint16  HandleEvent(void *event);
+  virtual void    URLNotify(const char *url, NPReason reason, 
+                            void *notifyData);
+  virtual NPError GetValue(NPPVariable variable, void *value);
+  virtual NPError SetValue(NPNVariable variable, void *value);
+  */
+
+private:
+  typedef vector<P3D_token> Tokens;
+  Tokens _tokens;
+  int _npp_mode;
+
+  P3D_instance *_inst;
+};
+
+#include "ppInstance.I"
+
+#endif

+ 24 - 0
direct/src/plugin_standalone/Sources.pp

@@ -0,0 +1,24 @@
+// This directory is still experimental.  Define HAVE_P3D_PLUGIN in
+// your Config.pp to build it.
+#define BUILD_DIRECTORY $[and $[HAVE_P3D_PLUGIN],$[HAVE_OPENSSL],$[HAVE_ZLIB]]
+
+#begin bin_target
+  #define USE_PACKAGES openssl zlib
+  #define TARGET panda3d
+
+  #define OTHER_LIBS \
+    prc:c dtoolutil:c dtoolbase:c dtool:m \
+    interrogatedb:c dconfig:c dtoolconfig:m \
+    express:c downloader:c pandaexpress:m \
+    pstatclient:c pandabase:c linmath:c putil:c \
+    pipeline:c panda:m \
+    pystub
+
+  #define OSX_SYS_FRAMEWORKS Foundation AppKit
+
+  #define SOURCES \
+    panda3d.cxx
+
+  #define WIN_SYS_LIBS user32.lib gdi32.lib shell32.lib
+
+#end bin_target

+ 42 - 112
direct/src/plugin/panda3d.cxx → direct/src/plugin_standalone/panda3d.cxx

@@ -30,11 +30,14 @@
 
 
 #include "httpClient.h"
 #include "httpClient.h"
 #include "httpChannel.h"
 #include "httpChannel.h"
-#include "Ramfile.h"
+#include "ramfile.h"
 #include "thread.h"
 #include "thread.h"
-#include "p3d_plugin.h"
 #include "pset.h"
 #include "pset.h"
 
 
+#include "../plugin/p3d_plugin.h"
+#include "../plugin/load_plugin_src.h"
+#include "../plugin/load_plugin_src.cxx"
+
 #ifndef HAVE_GETOPT
 #ifndef HAVE_GETOPT
   #include "gnu_getopt.h"
   #include "gnu_getopt.h"
 #else
 #else
@@ -43,28 +46,6 @@
   #endif
   #endif
 #endif
 #endif
 
 
-#ifdef _WIN32
-static const string dll_ext = ".dll";
-#elif defined(__APPLE__)
-static const string dll_ext = ".dylib";
-#else
-static const string dll_ext = ".so";
-#endif
-
-static const string default_plugin_filename = "libp3d_plugin";
-
-P3D_initialize_func *P3D_initialize;
-P3D_free_string_func *P3D_free_string;
-P3D_create_instance_func *P3D_create_instance;
-P3D_instance_finish_func *P3D_instance_finish;
-P3D_instance_has_property_func *P3D_instance_has_property;
-P3D_instance_get_property_func *P3D_instance_get_property;
-P3D_instance_set_property_func *P3D_instance_set_property;
-P3D_instance_get_request_func *P3D_instance_get_request;
-P3D_check_request_func *P3D_check_request;
-P3D_request_finish_func *P3D_request_finish;
-P3D_instance_feed_url_stream_func *P3D_instance_feed_url_stream;
-
 typedef pset<P3D_instance *> Instances;
 typedef pset<P3D_instance *> Instances;
 Instances _instances;
 Instances _instances;
 
 
@@ -154,81 +135,6 @@ thread_main() {
      bytes_sent, NULL, 0);
      bytes_sent, NULL, 0);
 }
 }
 
 
-bool
-load_plugin(const string &p3d_plugin_filename) {
-  string filename = p3d_plugin_filename;
-  if (filename.empty()) {
-    // Look for the plugin along the path.
-    filename = default_plugin_filename + dll_ext;
-  }
-
-#ifdef _WIN32
-  HMODULE module = LoadLibrary(filename.c_str());
-  if (module == NULL) {
-    // Couldn't load the DLL.
-    return false;
-  }
-
-  // Now get all of the function pointers.
-  P3D_initialize = (P3D_initialize_func *)GetProcAddress(module, "P3D_initialize");  
-  P3D_free_string = (P3D_free_string_func *)GetProcAddress(module, "P3D_free_string");  
-  P3D_create_instance = (P3D_create_instance_func *)GetProcAddress(module, "P3D_create_instance");  
-  P3D_instance_finish = (P3D_instance_finish_func *)GetProcAddress(module, "P3D_instance_finish");  
-  P3D_instance_has_property = (P3D_instance_has_property_func *)GetProcAddress(module, "P3D_instance_has_property");  
-  P3D_instance_get_property = (P3D_instance_get_property_func *)GetProcAddress(module, "P3D_instance_get_property");  
-  P3D_instance_set_property = (P3D_instance_set_property_func *)GetProcAddress(module, "P3D_instance_set_property");  
-  P3D_instance_get_request = (P3D_instance_get_request_func *)GetProcAddress(module, "P3D_instance_get_request");  
-  P3D_check_request = (P3D_check_request_func *)GetProcAddress(module, "P3D_check_request");  
-  P3D_request_finish = (P3D_request_finish_func *)GetProcAddress(module, "P3D_request_finish");  
-  P3D_instance_feed_url_stream = (P3D_instance_feed_url_stream_func *)GetProcAddress(module, "P3D_instance_feed_url_stream");  
-
-#else  // _WIN32
-  // Posix case.
-  void *module = dlopen(filename.c_str(), RTLD_NOW | RTLD_LOCAL);
-  if (module == NULL) {
-    // Couldn't load the .so.
-    return false;
-  }
-  
-  // Now get all of the function pointers.
-  P3D_initialize = (P3D_initialize_func *)dlsym(module, "P3D_initialize");  
-  P3D_free_string = (P3D_free_string_func *)dlsym(module, "P3D_free_string");  
-  P3D_create_instance = (P3D_create_instance_func *)dlsym(module, "P3D_create_instance");  
-  P3D_instance_finish = (P3D_instance_finish_func *)dlsym(module, "P3D_instance_finish");  
-  P3D_instance_has_property = (P3D_instance_has_property_func *)dlsym(module, "P3D_instance_has_property");  
-  P3D_instance_get_property = (P3D_instance_get_property_func *)dlsym(module, "P3D_instance_get_property");  
-  P3D_instance_set_property = (P3D_instance_set_property_func *)dlsym(module, "P3D_instance_set_property");  
-  P3D_instance_get_request = (P3D_instance_get_request_func *)dlsym(module, "P3D_instance_get_request");  
-  P3D_check_request = (P3D_check_request_func *)dlsym(module, "P3D_check_request");  
-  P3D_request_finish = (P3D_request_finish_func *)dlsym(module, "P3D_request_finish");  
-  P3D_instance_feed_url_stream = (P3D_instance_feed_url_stream_func *)dlsym(module, "P3D_instance_feed_url_stream");  
-
-#endif  // _WIN32
-
-  // Ensure that all of the function pointers have been found.
-  if (P3D_initialize == NULL ||
-      P3D_free_string == NULL ||
-      P3D_create_instance == NULL ||
-      P3D_instance_finish == NULL ||
-      P3D_instance_has_property == NULL ||
-      P3D_instance_get_property == NULL ||
-      P3D_instance_set_property == NULL ||
-      P3D_instance_get_request == NULL ||
-      P3D_check_request == NULL ||
-      P3D_request_finish == NULL ||
-      P3D_instance_feed_url_stream == NULL) {
-    return false;
-  }
-
-  // Successfully loaded.
-  if (!P3D_initialize(P3D_API_VERSION)) {
-    // Oops, failure to initialize.
-    return false;
-  }
-
-  return true;
-}
-
 void
 void
 handle_request(P3D_request *request) {
 handle_request(P3D_request *request) {
   bool handled = false;
   bool handled = false;
@@ -335,6 +241,35 @@ make_parent_window(P3D_window_handle &parent_window,
 
 
 #endif  // __APPLE__
 #endif  // __APPLE__
 
 
+P3D_instance *
+create_instance(const string &arg, P3D_window_type window_type,
+                int win_x, int win_y, int win_width, int win_height,
+                P3D_window_handle parent_window,
+                const string &output_filename) {
+
+  P3D_token tokens[] = {
+    { "output_filename", output_filename.c_str() },
+    { "src", arg.c_str() },
+  };
+  int num_tokens = sizeof(tokens) / sizeof(P3D_token);
+
+  // If the supplied parameter name is a real file, pass it in on the
+  // parameter list.  Otherwise, assume it's a URL and let the plugin
+  // download it.
+  Filename p3d_filename = Filename::from_os_specific(arg);
+  string os_p3d_filename;
+  if (p3d_filename.exists()) {
+    os_p3d_filename = p3d_filename.to_os_specific();
+  } 
+
+  P3D_instance *inst = P3D_create_instance
+    (NULL, os_p3d_filename.c_str(), 
+     window_type, win_x, win_y, win_width, win_height, parent_window,
+     tokens, num_tokens);
+
+  return inst;
+}
+
 void
 void
 usage() {
 usage() {
   cerr
   cerr
@@ -473,11 +408,6 @@ int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) {
 
 
   int num_instances = argc - 1;
   int num_instances = argc - 1;
 
 
-  P3D_token tokens[] = {
-    { "output_filename", output_filename.c_str() },
-  };
-  int num_tokens = sizeof(tokens) / sizeof(P3D_token);
-
   P3D_window_handle parent_window;
   P3D_window_handle parent_window;
   if (window_type == P3D_WT_embedded) {
   if (window_type == P3D_WT_embedded) {
     // The user asked for an embedded window.  Create a toplevel
     // The user asked for an embedded window.  Create a toplevel
@@ -518,10 +448,10 @@ int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) {
         int inst_x = win_x + xi * inst_width;
         int inst_x = win_x + xi * inst_width;
         int inst_y = win_y + yi * inst_height;
         int inst_y = win_y + yi * inst_height;
 
 
-        P3D_instance *inst = P3D_create_instance
-          (NULL, argv[i + 1], 
-           P3D_WT_embedded, inst_x, inst_y, inst_width, inst_height, parent_window,
-           tokens, num_tokens);
+        P3D_instance *inst = create_instance
+          (argv[i + 1], P3D_WT_embedded, 
+           inst_x, inst_y, inst_width, inst_height, parent_window,
+           output_filename);
         _instances.insert(inst);
         _instances.insert(inst);
       }
       }
     }
     }
@@ -529,10 +459,10 @@ int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) {
   } else {
   } else {
     // Not an embedded window.  Create each window with the same parameters.
     // Not an embedded window.  Create each window with the same parameters.
     for (int i = 0; i < num_instances; ++i) {
     for (int i = 0; i < num_instances; ++i) {
-      P3D_instance *inst = P3D_create_instance
-        (NULL, argv[i + 1], 
-         window_type, win_x, win_y, win_width, win_height, parent_window,
-         tokens, num_tokens);
+      P3D_instance *inst = create_instance
+        (argv[i + 1], window_type, 
+         win_x, win_y, win_width, win_height, parent_window,
+         output_filename);
       _instances.insert(inst);
       _instances.insert(inst);
     }
     }
   }
   }

+ 57 - 8
direct/src/showbase/RunAppMF.py

@@ -13,7 +13,7 @@ Also see MakeAppMF.py.
 
 
 import sys
 import sys
 from direct.showbase import VFSImporter
 from direct.showbase import VFSImporter
-from pandac.PandaModules import VirtualFileSystem, Filename, Multifile, loadPrcFileData, getModelPath
+from pandac.PandaModules import VirtualFileSystem, Filename, Multifile, loadPrcFileData, getModelPath, HTTPClient
 from direct.stdpy import file
 from direct.stdpy import file
 from direct.task.TaskManagerGlobal import taskMgr
 from direct.task.TaskManagerGlobal import taskMgr
 import os
 import os
@@ -91,22 +91,45 @@ def initPackedAppEnvironment():
     # we plan to mount there.
     # we plan to mount there.
     vfs.chdir(MultifileRoot)
     vfs.chdir(MultifileRoot)
 
 
-def runPackedApp(args):
-    if not args:
-        raise ArgumentError, "No Panda app specified.  Use:\npython RunAppMF.py app.mf"
+def runPackedApp(p3dFilename, tokens = []):
+    tokenDict = dict(tokens)
+    fname = Filename.fromOsSpecific(p3dFilename)
+    if not p3dFilename:
+        # If we didn't get a literal filename, we have to download it
+        # from the URL.  TODO: make this a smarter temporary filename?
+        fname = Filename.temporary('', 'p3d_')
+        fname.setExtension('p3d')
+        p3dFilename = fname.toOsSpecific()
+        src = tokenDict.get('src', None)
+        if not src:
+            raise ArgumentError, "No Panda app specified."
+            
+        http = HTTPClient.getGlobalPtr()
+        hc = http.getDocument(src)
+        if not hc.downloadToFile(fname):
+            fname.unlink()
+            raise ArgumentError, "Couldn't download %s" % (src)
+
+        # Set a hook on sys.exit to delete the temporary file.
+        oldexitfunc = getattr(sys, 'exitfunc', None)
+        def deleteTempFile(fname = fname, oldexitfunc = oldexitfunc):
+            fname.unlink()
+            if oldexitfunc:
+                oldexitfunc()
+
+        sys.exitfunc = deleteTempFile
 
 
     vfs = VirtualFileSystem.getGlobalPtr()
     vfs = VirtualFileSystem.getGlobalPtr()
 
 
-    fname = Filename.fromOsSpecific(args[0])
     if not vfs.exists(fname):
     if not vfs.exists(fname):
-        raise ArgumentError, "No such file: %s" % (args[0])
+        raise ArgumentError, "No such file: %s" % (p3dFilename)
 
 
     fname.makeAbsolute()
     fname.makeAbsolute()
     initPackedAppEnvironment()
     initPackedAppEnvironment()
 
 
     mf = Multifile()
     mf = Multifile()
     if not mf.openRead(fname):
     if not mf.openRead(fname):
-        raise ArgumentError, "Not a Panda Multifile: %s" % (args[0])
+        raise ArgumentError, "Not a Panda Multifile: %s" % (p3dFilename)
 
 
     # Mount the Multifile under /mf, by convention.
     # Mount the Multifile under /mf, by convention.
     vfs.mount(mf, MultifileRoot, vfs.MFReadOnly)
     vfs.mount(mf, MultifileRoot, vfs.MFReadOnly)
@@ -150,9 +173,35 @@ def setupWindow(windowType, x, y, width, height, parent):
 
 
     loadPrcFileData("setupWindow", data)
     loadPrcFileData("setupWindow", data)
 
 
+def parseSysArgs():
+    """ Converts sys.argv into (p3dFilename, tokens). """
+    if len(sys.argv) < 2 or not sys.argv[1]:
+        raise ArgumentError, "No Panda app specified.  Use:\npython RunAppMF.py app.mf"
+
+    tokens = []
+    for token in sys.argv[2:]:
+        if '=' in token:
+            keyword, value = token.split('=', 1)
+        else:
+            keyword = token
+            value = ''
+        tokens.append((keyword.lower(), value))
+
+    p3dFilename = Filename.fromOsSpecific(sys.argv[1])
+    osFilename = p3dFilename.toOsSpecific()
+    if not p3dFilename.exists():
+        # If the filename doesn't exist, it must be a URL.
+        osFilename = ''
+        if 'src' not in dict(tokens):
+            tokens.append(('src', sys.argv[1]))
+
+    return (osFilename, tokens)
+        
+        
+
 if __name__ == '__main__':
 if __name__ == '__main__':
     try:
     try:
-        runPackedApp(sys.argv[1:])
+        runPackedApp(*parseSysArgs())
     except ArgumentError, e:
     except ArgumentError, e:
         print e.args[0]
         print e.args[0]
         sys.exit(1)
         sys.exit(1)

+ 12 - 0
direct/src/showbase/ShowBase.py

@@ -102,6 +102,11 @@ class ShowBase(DirectObject.DirectObject):
         # the program by closing the main window.
         # the program by closing the main window.
         self.exitFunc = None
         self.exitFunc = None
 
 
+        # Add final-exit callbacks to this list.  These will be called
+        # when sys.exit() is called, after Panda has unloaded, and
+        # just before Python is about to shut down.
+        self.finalExitCallbacks = []
+
         Task.TaskManager.taskTimerVerbose = self.config.GetBool('task-timer-verbose', 0)
         Task.TaskManager.taskTimerVerbose = self.config.GetBool('task-timer-verbose', 0)
         Task.TaskManager.extendedExceptions = self.config.GetBool('extended-exceptions', 0)
         Task.TaskManager.extendedExceptions = self.config.GetBool('extended-exceptions', 0)
         Task.TaskManager.pStatsTasks = self.config.GetBool('pstats-tasks', 0)
         Task.TaskManager.pStatsTasks = self.config.GetBool('pstats-tasks', 0)
@@ -444,6 +449,13 @@ class ShowBase(DirectObject.DirectObject):
             del self.winList
             del self.winList
             del self.pipe
             del self.pipe
 
 
+        vfs = VirtualFileSystem.getGlobalPtr()
+        vfs.unmountAll()
+
+        for cb in self.finalExitCallbacks:
+            cb()
+        
+
     def exitfunc(self):
     def exitfunc(self):
         """
         """
         This should be assigned to sys.exitfunc to be called just
         This should be assigned to sys.exitfunc to be called just