浏览代码

embed plugin windows within OSX browsers properly

David Rose 16 年之前
父节点
当前提交
9fa212a48a

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

@@ -6,6 +6,8 @@
   #define USE_PACKAGES tinyxml openssl zlib jpeg x11
   #define USE_PACKAGES tinyxml openssl zlib jpeg x11
   #define TARGET p3d_plugin
   #define TARGET p3d_plugin
   #define LIB_PREFIX
   #define LIB_PREFIX
+
+  #define OTHER_LIBS subprocbuffer
   
   
   // We need this because we don't
   // We need this because we don't
   // include dtool_config.h.
   // include dtool_config.h.

+ 2 - 2
direct/src/plugin/handleStream.I

@@ -39,7 +39,7 @@ inline HandleStream::
 //               output.
 //               output.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 inline void HandleStream::
 inline void HandleStream::
-open_read(Handle handle) {
+open_read(FHandle handle) {
   clear((ios::iostate)0);
   clear((ios::iostate)0);
   _buf.open_read(handle);
   _buf.open_read(handle);
   if (!_buf.is_open_read()) {
   if (!_buf.is_open_read()) {
@@ -55,7 +55,7 @@ open_read(Handle handle) {
 //               output.
 //               output.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 inline void HandleStream::
 inline void HandleStream::
-open_write(Handle handle) {
+open_write(FHandle handle) {
   clear((ios::iostate)0);
   clear((ios::iostate)0);
   _buf.open_write(handle);
   _buf.open_write(handle);
   if (!_buf.is_open_write()) {
   if (!_buf.is_open_write()) {

+ 2 - 2
direct/src/plugin/handleStream.h

@@ -29,8 +29,8 @@ public:
   inline HandleStream();
   inline HandleStream();
   inline ~HandleStream();
   inline ~HandleStream();
 
 
-  inline void open_read(Handle handle);
-  inline void open_write(Handle handle);
+  inline void open_read(FHandle handle);
+  inline void open_write(FHandle handle);
   inline void close();
   inline void close();
 
 
 private:
 private:

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

@@ -69,7 +69,7 @@ HandleStreamBuf::
 //               output.
 //               output.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void HandleStreamBuf::
 void HandleStreamBuf::
-open_read(Handle handle) {
+open_read(FHandle handle) {
   close();
   close();
 
 
   _handle = handle;
   _handle = handle;
@@ -84,7 +84,7 @@ open_read(Handle handle) {
 //               output.
 //               output.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void HandleStreamBuf::
 void HandleStreamBuf::
-open_write(Handle handle) {
+open_write(FHandle handle) {
   close();
   close();
 
 
   _handle = handle;
   _handle = handle;

+ 5 - 5
direct/src/plugin/handleStreamBuf.h

@@ -17,10 +17,10 @@
 
 
 #ifdef _WIN32
 #ifdef _WIN32
 #include <windows.h>
 #include <windows.h>
-typedef HANDLE Handle;
+typedef HANDLE FHandle;
 #else
 #else
 // On POSIX, we use a file descriptor as a "handle".
 // On POSIX, we use a file descriptor as a "handle".
-typedef int Handle;
+typedef int FHandle;
 #endif
 #endif
 
 
 #include <iostream>
 #include <iostream>
@@ -37,8 +37,8 @@ public:
   HandleStreamBuf();
   HandleStreamBuf();
   virtual ~HandleStreamBuf();
   virtual ~HandleStreamBuf();
 
 
-  void open_read(Handle handle);
-  void open_write(Handle handle);
+  void open_read(FHandle handle);
+  void open_write(FHandle handle);
   bool is_open_read() const;
   bool is_open_read() const;
   bool is_open_write() const;
   bool is_open_write() const;
   void close();
   void close();
@@ -56,7 +56,7 @@ private:
   bool _is_open_read;
   bool _is_open_read;
   bool _is_open_write;
   bool _is_open_write;
 
 
-  Handle _handle;
+  FHandle _handle;
 
 
   char *_buffer;
   char *_buffer;
 };
 };

+ 6 - 1
direct/src/plugin/load_plugin.cxx

@@ -69,6 +69,7 @@ P3D_instance_get_request_func *P3D_instance_get_request;
 P3D_check_request_func *P3D_check_request;
 P3D_check_request_func *P3D_check_request;
 P3D_request_finish_func *P3D_request_finish;
 P3D_request_finish_func *P3D_request_finish;
 P3D_instance_feed_url_stream_func *P3D_instance_feed_url_stream;
 P3D_instance_feed_url_stream_func *P3D_instance_feed_url_stream;
+P3D_instance_handle_event_func *P3D_instance_handle_event;
 
 
 #ifdef _WIN32
 #ifdef _WIN32
 static HMODULE module = NULL;
 static HMODULE module = NULL;
@@ -206,6 +207,7 @@ load_plugin(const string &p3d_plugin_filename) {
   P3D_check_request = (P3D_check_request_func *)get_func(module, "P3D_check_request");  
   P3D_check_request = (P3D_check_request_func *)get_func(module, "P3D_check_request");  
   P3D_request_finish = (P3D_request_finish_func *)get_func(module, "P3D_request_finish");  
   P3D_request_finish = (P3D_request_finish_func *)get_func(module, "P3D_request_finish");  
   P3D_instance_feed_url_stream = (P3D_instance_feed_url_stream_func *)get_func(module, "P3D_instance_feed_url_stream");  
   P3D_instance_feed_url_stream = (P3D_instance_feed_url_stream_func *)get_func(module, "P3D_instance_feed_url_stream");  
+  P3D_instance_handle_event = (P3D_instance_handle_event_func *)get_func(module, "P3D_instance_handle_event");  
 
 
   #undef get_func
   #undef get_func
 
 
@@ -244,7 +246,8 @@ load_plugin(const string &p3d_plugin_filename) {
       P3D_instance_get_request == NULL ||
       P3D_instance_get_request == NULL ||
       P3D_check_request == NULL ||
       P3D_check_request == NULL ||
       P3D_request_finish == NULL ||
       P3D_request_finish == NULL ||
-      P3D_instance_feed_url_stream == NULL) {
+      P3D_instance_feed_url_stream == NULL ||
+      P3D_instance_handle_event == NULL) {
     
     
     cerr
     cerr
       << "Some function pointers not found:"
       << "Some function pointers not found:"
@@ -283,6 +286,7 @@ load_plugin(const string &p3d_plugin_filename) {
       << "\nP3D_check_request = " << P3D_check_request
       << "\nP3D_check_request = " << P3D_check_request
       << "\nP3D_request_finish = " << P3D_request_finish
       << "\nP3D_request_finish = " << P3D_request_finish
       << "\nP3D_instance_feed_url_stream = " << P3D_instance_feed_url_stream
       << "\nP3D_instance_feed_url_stream = " << P3D_instance_feed_url_stream
+      << "\nP3D_instance_handle_event = " << P3D_instance_handle_event
       << "\n";
       << "\n";
     return false;
     return false;
   }
   }
@@ -376,6 +380,7 @@ unload_dso() {
   P3D_check_request = NULL;
   P3D_check_request = NULL;
   P3D_request_finish = NULL;
   P3D_request_finish = NULL;
   P3D_instance_feed_url_stream = NULL;
   P3D_instance_feed_url_stream = NULL;
+  P3D_instance_handle_event = NULL;
 
 
   plugin_loaded = false;
   plugin_loaded = false;
 }
 }

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

@@ -55,6 +55,7 @@ extern P3D_instance_get_request_func *P3D_instance_get_request;
 extern P3D_check_request_func *P3D_check_request;
 extern P3D_check_request_func *P3D_check_request;
 extern P3D_request_finish_func *P3D_request_finish;
 extern P3D_request_finish_func *P3D_request_finish;
 extern P3D_instance_feed_url_stream_func *P3D_instance_feed_url_stream;
 extern P3D_instance_feed_url_stream_func *P3D_instance_feed_url_stream;
+extern P3D_instance_handle_event_func *P3D_instance_handle_event;
 
 
 string get_plugin_basename();
 string get_plugin_basename();
 bool load_plugin(const string &p3d_plugin_filename);
 bool load_plugin(const string &p3d_plugin_filename);

+ 197 - 3
direct/src/plugin/p3dInstance.cxx

@@ -27,15 +27,17 @@
 #include <sstream>
 #include <sstream>
 #include <algorithm>
 #include <algorithm>
 
 
+#ifdef __APPLE__
+#include <sys/mman.h>
+#endif  // __APPLE__
+
 #ifdef _WIN32
 #ifdef _WIN32
 typedef P3DWinSplashWindow SplashWindowType;
 typedef P3DWinSplashWindow SplashWindowType;
-#else
-#ifdef HAVE_X11
+#elif defined(HAVE_X11)
 typedef P3DX11SplashWindow SplashWindowType;
 typedef P3DX11SplashWindow SplashWindowType;
 #else
 #else
 typedef P3DSplashWindow SplashWindowType;
 typedef P3DSplashWindow SplashWindowType;
 #endif
 #endif
-#endif
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: P3DInstance::Constructor
 //     Function: P3DInstance::Constructor
@@ -63,6 +65,13 @@ P3DInstance(P3D_request_ready_func *func, void *user_data) :
   _instance_window_opened = false;
   _instance_window_opened = false;
   _requested_stop = false;
   _requested_stop = false;
 
 
+#ifdef __APPLE__
+  _shared_fd = -1;
+  _shared_mmap_size = 0;
+  _swbuffer = NULL;
+  _reversed_buffer = NULL;
+#endif  // __APPLE__
+
   // Set some initial properties.
   // Set some initial properties.
   _panda_script_object->set_float_property("downloadProgress", 0.0);
   _panda_script_object->set_float_property("downloadProgress", 0.0);
 }
 }
@@ -95,6 +104,19 @@ P3DInstance::
     _splash_window = NULL;
     _splash_window = NULL;
   }
   }
 
 
+#ifdef __APPLE__
+  if (_swbuffer != NULL) {
+    SubprocessWindowBuffer::destroy_buffer(_shared_fd, _shared_mmap_size,
+                                           _shared_filename, _swbuffer);
+    _swbuffer = NULL;
+  }
+
+  if (_reversed_buffer != NULL) {
+    delete[] _reversed_buffer;
+    _reversed_buffer = NULL;
+  }
+#endif    
+
   DESTROY_LOCK(_request_lock);
   DESTROY_LOCK(_request_lock);
 
 
   // TODO: empty _raw_requests and _baked_requests queues, and
   // TODO: empty _raw_requests and _baked_requests queues, and
@@ -184,6 +206,24 @@ set_wparams(const P3DWindowParams &wparams) {
     xcommand->SetAttribute("cmd", "setup_window");
     xcommand->SetAttribute("cmd", "setup_window");
     xcommand->SetAttribute("instance_id", get_instance_id());
     xcommand->SetAttribute("instance_id", get_instance_id());
     TiXmlElement *xwparams = _wparams.make_xml();
     TiXmlElement *xwparams = _wparams.make_xml();
+
+#ifdef __APPLE__
+    // On Mac, we have to communicate the results of the rendering
+    // back via shared memory, instead of directly parenting windows
+    // to the browser.  Set up this mechanism.
+    int x_size = _wparams.get_win_width();
+    int y_size = _wparams.get_win_height();
+    nout << "size = " << x_size << " * " << y_size << "\n" << flush;
+    if (_shared_fd == -1 && x_size != 0 && y_size != 0) {
+      _swbuffer = SubprocessWindowBuffer::new_buffer
+        (_shared_fd, _shared_mmap_size, _shared_filename, x_size, y_size);
+      if (_swbuffer != NULL) {
+        _reversed_buffer = new char[_swbuffer->get_framebuffer_size()];
+      }
+
+      xwparams->SetAttribute("subprocess_window", _shared_filename);
+    }
+#endif   // __APPLE__
     
     
     doc->LinkEndChild(decl);
     doc->LinkEndChild(decl);
     doc->LinkEndChild(xcommand);
     doc->LinkEndChild(xcommand);
@@ -425,6 +465,85 @@ feed_url_stream(int unique_id,
   return download_ok;
   return download_ok;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: P3DInstance::handle_event
+//       Access: Public
+//  Description: Responds to the os-generated window event.
+////////////////////////////////////////////////////////////////////
+void P3DInstance::
+handle_event(P3D_event_data event) {
+#ifdef _WIN32
+  // This function is not used in Win32 and does nothing.
+
+#elif defined(__APPLE__)
+  EventRecord *er = event._event;
+
+  switch (er->what) {
+  case nullEvent:
+    break;
+
+  case mouseDown:
+  case mouseUp:
+    {
+      Point pt = er->where;
+      GlobalToLocal(&pt);
+      P3D_window_handle window = _wparams.get_parent_window();
+      cerr << "mouse " << pt.h << " " << pt.v << "\n";
+      if (_swbuffer != NULL) {
+        SubprocessWindowBuffer::Event swb_event;
+        swb_event._up = (er->what == mouseUp);
+        swb_event._x = pt.h;
+        swb_event._y = pt.v;
+        _swbuffer->add_event(swb_event);
+      }
+    }
+    break;
+
+  case keyDown:
+  case keyUp:
+  case autoKey:
+    cerr << "keycode: " << (er->message & 0xffff) << "\n";
+    break;
+
+  case updateEvt:
+    paint_window();
+    break;
+
+  case activateEvt:
+    cerr << "activate window: " << er->message << "\n";
+    break;
+
+  case diskEvt:
+    break;
+
+  case osEvt:
+    if ((er->message & 0xf0000000) == suspendResumeMessage) {
+      if (er->message & 1) {
+        cerr << "suspend\n";
+      } else {
+        cerr << "resume\n";
+      }
+    } else if ((er->message & 0xf0000000) == mouseMovedMessage) {
+      cerr << "mouse moved\n";
+    } else {
+      cerr << "unhandled osEvt: " << hex << er->message << dec << "\n";
+    }
+    break;
+
+  case kHighLevelEvent:
+    cerr << "high level: " << er->message << "\n";
+    break;
+
+  default:
+    cerr << "unhandled event: " << er->what << ", " << er->message << "\n";
+    break;
+  }
+
+#elif defined(HAVE_X11)
+
+#endif
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: P3DInstance::add_package
 //     Function: P3DInstance::add_package
 //       Access: Public
 //       Access: Public
@@ -811,6 +930,81 @@ install_progress(P3DPackage *package, double progress) {
   _panda_script_object->set_float_property("downloadProgress", progress);
   _panda_script_object->set_float_property("downloadProgress", progress);
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: P3DInstance::paint_window
+//       Access: Private
+//  Description: Actually paints the rendered image to the browser
+//               window.  This is only implemented (and needed) for
+//               OSX, where the child process isn't allowed to do it
+//               directly.
+////////////////////////////////////////////////////////////////////
+void P3DInstance::
+paint_window() {
+#ifdef __APPLE__
+  if (_swbuffer == NULL) {
+    nout << "no _swbuffer\n";
+    return;
+  }
+
+  QDErr err;
+
+  // blit rendered framebuffer into window backing store
+  int x_size = min(_wparams.get_win_width(), _swbuffer->get_x_size());
+  int y_size = min(_wparams.get_win_height(), _swbuffer->get_y_size());
+  Rect src_rect = {0, 0, y_size, x_size};
+  Rect ddrc_rect = {0, 0, y_size, x_size};
+
+  size_t rowsize = _swbuffer->get_row_size();
+
+  if (_swbuffer->ready_for_read()) {
+    // Copy the new framebuffer image from the child process.
+    const void *framebuffer = _swbuffer->open_read_framebuffer();
+    
+    // We have to reverse the image vertically first (different
+    // conventions between Panda and Mac).
+    for (int yi = 0; yi < y_size; ++yi) {
+      memcpy(_reversed_buffer + (y_size - 1 - yi) * rowsize,
+             (char *)framebuffer + yi * rowsize,
+             rowsize);
+    }
+    
+    _swbuffer->close_read_framebuffer();
+
+  } else {
+    // No frame ready.  Just re-paint the frame we had saved last
+    // time.
+  }
+
+  // create a GWorld containing our image
+  GWorldPtr pGWorld;
+  err = NewGWorldFromPtr(&pGWorld, k32BGRAPixelFormat, &src_rect, 0, 0, 0, 
+                         _reversed_buffer, rowsize);
+  if (err != noErr) {
+    nout << " error in NewGWorldFromPtr, called from paint_window()\n";
+    return;
+  }
+
+  GrafPtr out_port = _wparams.get_parent_window()._port;
+  GrafPtr portSave = NULL;
+  Boolean portChanged = QDSwapPort(out_port, &portSave);
+
+  // Make sure the clipping rectangle isn't in the way.  Is there a
+  // better way to eliminate the cliprect from consideration?
+  Rect r = { 0, 0, 0x7fff, 0x7fff }; 
+  ClipRect(&r);
+
+  CopyBits(GetPortBitMapForCopyBits(pGWorld), 
+           GetPortBitMapForCopyBits(out_port), 
+           &src_rect, &ddrc_rect, srcCopy, 0);
+  
+  if (portChanged) {
+    QDSwapPort(portSave, NULL);
+  }
+  
+  DisposeGWorld(pGWorld);
+#endif  // __APPLE__  
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: P3DInstance::SplashDownload::Constructor
 //     Function: P3DInstance::SplashDownload::Constructor
 //       Access: Public
 //       Access: Public

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

@@ -22,6 +22,10 @@
 #include "p3dReferenceCount.h"
 #include "p3dReferenceCount.h"
 #include "get_tinyxml.h"
 #include "get_tinyxml.h"
 
 
+#ifdef __APPLE__
+#include "subprocessWindowBuffer.h"
+#endif
+
 #include <deque>
 #include <deque>
 #include <map>
 #include <map>
 
 
@@ -65,6 +69,8 @@ public:
                        const unsigned char *this_data, 
                        const unsigned char *this_data, 
                        size_t this_data_size);
                        size_t this_data_size);
 
 
+  void handle_event(P3D_event_data event);
+
   inline int get_instance_id() const;
   inline int get_instance_id() const;
   inline const string &get_session_key() const;
   inline const string &get_session_key() const;
   inline const string &get_python_version() const;
   inline const string &get_python_version() const;
@@ -101,6 +107,8 @@ private:
   void make_splash_window();
   void make_splash_window();
   void install_progress(P3DPackage *package, double progress);
   void install_progress(P3DPackage *package, double progress);
 
 
+  void paint_window();
+
   P3D_request_ready_func *_func;
   P3D_request_ready_func *_func;
   P3D_object *_browser_script_object;
   P3D_object *_browser_script_object;
   P3DToplevelObject *_panda_script_object;
   P3DToplevelObject *_panda_script_object;
@@ -118,6 +126,17 @@ private:
   // Not ref-counted: session is the parent.
   // Not ref-counted: session is the parent.
   P3DSession *_session;
   P3DSession *_session;
 
 
+#ifdef __APPLE__
+  // On OSX, we have to get a copy of the framebuffer data back from
+  // the child process, and draw it to the window, here in the parent
+  // process.  Crazy!
+  int _shared_fd;
+  size_t _shared_mmap_size;
+  string _shared_filename;
+  SubprocessWindowBuffer *_swbuffer;
+  char *_reversed_buffer;
+#endif __APPLE__
+
   P3DSplashWindow *_splash_window;
   P3DSplashWindow *_splash_window;
   bool _instance_window_opened;
   bool _instance_window_opened;
 
 

+ 15 - 5
direct/src/plugin/p3dPythonRun.cxx

@@ -889,27 +889,37 @@ setup_window(P3DCInstance *inst, TiXmlElement *xwparams) {
   xwparams->Attribute("win_height", &win_height);
   xwparams->Attribute("win_height", &win_height);
 
 
   long parent_window_handle = 0;
   long parent_window_handle = 0;
+  const char *subprocess_window = "";
 
 
 #ifdef _WIN32
 #ifdef _WIN32
   int hwnd;
   int hwnd;
   if (xwparams->Attribute("parent_hwnd", &hwnd)) {
   if (xwparams->Attribute("parent_hwnd", &hwnd)) {
     parent_window_handle = (long)hwnd;
     parent_window_handle = (long)hwnd;
   }
   }
-#endif
-#ifdef HAVE_X11
+
+#elif __APPLE__
+  // On Mac, we don't parent windows directly to the browser; instead,
+  // we have to go through this subprocess-window nonsense.
+
+  subprocess_window = xwparams->Attribute("subprocess_window");
+  if (subprocess_window == NULL) {
+    subprocess_window = "";
+  }
+
+#elif defined(HAVE_X11)
   // Bad! Casting to int loses precision.
   // Bad! Casting to int loses precision.
   int xwindow;
   int xwindow;
   if (xwparams->Attribute("parent_xwindow", &xwindow)) {
   if (xwparams->Attribute("parent_xwindow", &xwindow)) {
-    parent_window_handle = (unsigned long)xwindow;
+    parent_window_handle = (long)xwindow;
   }
   }
 #endif
 #endif
 
 
   // TODO: direct this into the particular instance.  This will
   // TODO: direct this into the particular instance.  This will
   // require a specialized ShowBase replacement.
   // require a specialized ShowBase replacement.
   PyObject *result = PyObject_CallMethod
   PyObject *result = PyObject_CallMethod
-    (_runner, (char *)"setupWindow", (char *)"siiiii", window_type.c_str(),
+    (_runner, (char *)"setupWindow", (char *)"siiiiis", window_type.c_str(),
      win_x, win_y, win_width, win_height,
      win_x, win_y, win_width, win_height,
-     parent_window_handle);
+     parent_window_handle, subprocess_window);
   if (result == NULL) {
   if (result == NULL) {
     PyErr_Print();
     PyErr_Print();
   }
   }

+ 5 - 2
direct/src/plugin/p3dWindowParams.cxx

@@ -79,8 +79,11 @@ make_xml() {
     xwparams->SetAttribute("win_height", _win_height);
     xwparams->SetAttribute("win_height", _win_height);
 #ifdef _WIN32
 #ifdef _WIN32
     xwparams->SetAttribute("parent_hwnd", (int)_parent_window._hwnd);
     xwparams->SetAttribute("parent_hwnd", (int)_parent_window._hwnd);
-#endif
-#ifdef HAVE_X11
+
+#elif defined(__APPLE__)
+    // The subprocess_window setting is applied by the caller.
+
+#elif defined(HAVE_X11)
     xwparams->SetAttribute("parent_xwindow", (unsigned long)_parent_window._xwindow);
     xwparams->SetAttribute("parent_xwindow", (unsigned long)_parent_window._xwindow);
 #endif
 #endif
     break;
     break;

+ 8 - 0
direct/src/plugin/p3d_plugin.cxx

@@ -406,3 +406,11 @@ P3D_instance_feed_url_stream(P3D_instance *instance, int unique_id,
   RELEASE_LOCK(_api_lock);
   RELEASE_LOCK(_api_lock);
   return result;
   return result;
 }
 }
+
+void
+P3D_instance_handle_event(P3D_instance *instance, P3D_event_data event) {
+  assert(P3DInstanceManager::get_global_ptr()->is_initialized());
+  ACQUIRE_LOCK(_api_lock);
+  ((P3DInstance *)instance)->handle_event(event);
+  RELEASE_LOCK(_api_lock);
+}

+ 33 - 5
direct/src/plugin/p3d_plugin.h

@@ -57,6 +57,10 @@
 
 
 #endif  /* _WIN32 */
 #endif  /* _WIN32 */
 
 
+#ifdef __APPLE__
+#include <Carbon/Carbon.h>
+#endif  /* __APPLE__ */
+
 #ifdef __cplusplus
 #ifdef __cplusplus
 extern "C" {
 extern "C" {
 #endif
 #endif
@@ -130,14 +134,14 @@ typedef struct {
 typedef struct {
 typedef struct {
 #ifdef _WIN32
 #ifdef _WIN32
   HWND _hwnd;
   HWND _hwnd;
-#endif
-#ifdef HAVE_X11
+
+#elif defined(__APPLE__)
+  GrafPtr _port;
+
+#elif defined(HAVE_X11)
   unsigned long _xwindow;
   unsigned long _xwindow;
   void *_xdisplay;
   void *_xdisplay;
 #endif
 #endif
-#ifdef __APPLE__
-  void *_nswindow;
-#endif
 } P3D_window_handle;
 } P3D_window_handle;
 
 
 /* This enum lists the different kinds of window types that may be
 /* This enum lists the different kinds of window types that may be
@@ -781,6 +785,29 @@ P3D_instance_feed_url_stream_func(P3D_instance *instance, int unique_id,
                                   const void *this_data, 
                                   const void *this_data, 
                                   size_t this_data_size);
                                   size_t this_data_size);
 
 
+/* This structure abstracts out the event pointer data types for the
+   different platforms, as passed to P3D_instance_handle_event(),
+   below. */
+typedef struct {
+#ifdef _WIN32
+  // Not used for Win32.
+
+#elif defined(__APPLE__)
+  EventRecord *_event;
+
+#elif defined(HAVE_X11)
+  //  XEvent *_event; ?
+#endif
+} P3D_event_data;
+
+/* Use this function to supply a new os-specific window event to the
+   plugin.  This is presently used only on OSX, where the window
+   events are needed for proper plugin handling; and possibly also on
+   X11.  On Windows, window events are handled natively by the plugin.
+*/
+typedef void
+P3D_instance_handle_event_func(P3D_instance *instance, P3D_event_data event);
+
 #ifdef P3D_FUNCTION_PROTOTYPES
 #ifdef P3D_FUNCTION_PROTOTYPES
 
 
 /* Define all of the actual prototypes for the above functions. */
 /* Define all of the actual prototypes for the above functions. */
@@ -820,6 +847,7 @@ EXPCL_P3D_PLUGIN P3D_instance_get_request_func P3D_instance_get_request;
 EXPCL_P3D_PLUGIN P3D_check_request_func P3D_check_request;
 EXPCL_P3D_PLUGIN P3D_check_request_func P3D_check_request;
 EXPCL_P3D_PLUGIN P3D_request_finish_func P3D_request_finish;
 EXPCL_P3D_PLUGIN P3D_request_finish_func P3D_request_finish;
 EXPCL_P3D_PLUGIN P3D_instance_feed_url_stream_func P3D_instance_feed_url_stream;
 EXPCL_P3D_PLUGIN P3D_instance_feed_url_stream_func P3D_instance_feed_url_stream;
+EXPCL_P3D_PLUGIN P3D_instance_handle_event_func P3D_instance_handle_event;
 
 
 #endif  /* P3D_FUNCTION_PROTOTYPES */
 #endif  /* P3D_FUNCTION_PROTOTYPES */
 
 

+ 64 - 6
direct/src/plugin_npapi/ppInstance.cxx

@@ -438,7 +438,7 @@ handle_request(P3D_request *request) {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PPInstance::handle_request_loop
 //     Function: PPInstance::handle_request_loop
-//       Access: Private, Static
+//       Access: Public, Static
 //  Description: Checks for any new requests from the plugin, and
 //  Description: Checks for any new requests from the plugin, and
 //               dispatches them to the appropriate PPInstance.  This
 //               dispatches them to the appropriate PPInstance.  This
 //               function is called only in the main thread.
 //               function is called only in the main thread.
@@ -461,6 +461,47 @@ handle_request_loop() {
   }
   }
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: PPInstance::handle_event
+//       Access: Public
+//  Description: Called by the browser as new window events are
+//               generated.
+////////////////////////////////////////////////////////////////////
+void PPInstance::
+handle_event(void *event) {
+  // This is a good time to check for new requests.
+  handle_request_loop();
+
+  if (_p3d_inst == NULL) {
+    // Ignore events that come in before we've launched the instance.
+    return;
+  }
+
+#ifdef __APPLE__
+  EventRecord *er = (EventRecord *)event;
+
+  switch (er->what) {
+  case nullEvent:
+    // We appear to get this event pretty frequently when nothing else
+    // is going on.  Great; we'll take advantage of it to invalidate
+    // the instance rectangle, which will cause updateEvt to be
+    // triggered (if the instance is still onscreen).
+
+    if (_got_window) {
+      NPRect rect = { 0, 0, _window.height, _window.width };
+      browser->invalidaterect(_npp_instance, &rect);
+    }
+    break;
+  }
+
+  // All other events we feed down to the plugin for processing.
+  P3D_event_data edata;
+  edata._event = er;
+  P3D_instance_handle_event(_p3d_inst, edata);
+
+#endif  // __APPLE__
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PPInstance::get_panda_script_object
 //     Function: PPInstance::get_panda_script_object
 //       Access: Public
 //       Access: Public
@@ -972,14 +1013,24 @@ send_window() {
     // right spot.
     // right spot.
 #ifdef _WIN32
 #ifdef _WIN32
     parent_window._hwnd = (HWND)(_window.window);
     parent_window._hwnd = (HWND)(_window.window);
-#endif
-#ifdef HAVE_X11
+    x = 0;
+    y = 0;
+
+#elif defined(__APPLE__)
+    logfile << "windowed plugin\n" << flush;
+    NP_Port *port = (NP_Port *)_window.window;
+    logfile << "portx, porty = " << port->portx << ", " << port->porty << "\n";
+    logfile << "x, y = " << _window.x << ", " << _window.y << "\n";
+    parent_window._port = port->port;
+
+#elif defined(HAVE_X11)
     // We make it an 'unsigned long' instead of 'Window'
     // We make it an 'unsigned long' instead of 'Window'
     // to avoid nppanda3d.so getting a dependency on X11.
     // to avoid nppanda3d.so getting a dependency on X11.
     parent_window._xwindow = (unsigned long)(_window.window);
     parent_window._xwindow = (unsigned long)(_window.window);
-#endif
     x = 0;
     x = 0;
     y = 0;
     y = 0;
+#endif
+
   } else {
   } else {
     // We have a "windowless" plugin.  Parent our window directly to
     // We have a "windowless" plugin.  Parent our window directly to
     // the browser window.
     // the browser window.
@@ -990,8 +1041,15 @@ send_window() {
                           &hwnd) == NPERR_NO_ERROR) {
                           &hwnd) == NPERR_NO_ERROR) {
       parent_window._hwnd = hwnd;
       parent_window._hwnd = hwnd;
     }
     }
-#endif
-#ifdef HAVE_X11
+
+#elif defined(__APPLE__)
+    logfile << "windowless plugin\n" << flush;
+    NP_Port *port = (NP_Port *)_window.window;
+    logfile << "portx, porty = " << port->portx << ", " << port->porty << "\n";
+    logfile << "x, y = " << _window.x << ", " << _window.y << "\n";
+    parent_window._port = port->port;
+
+#elif defined(HAVE_X11)
     parent_window._xwindow = 0;
     parent_window._xwindow = 0;
     unsigned long win;
     unsigned long win;
     if (browser->getvalue(_npp_instance, NPNVnetscapeWindow,
     if (browser->getvalue(_npp_instance, NPNVnetscapeWindow,

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

@@ -53,6 +53,8 @@ public:
   void handle_request(P3D_request *request);
   void handle_request(P3D_request *request);
   static void handle_request_loop();
   static void handle_request_loop();
 
 
+  void handle_event(void *event);
+
   NPObject *get_panda_script_object();
   NPObject *get_panda_script_object();
 
 
   void p3dobj_to_variant(NPVariant *result, P3D_object *object);
   void p3dobj_to_variant(NPVariant *result, P3D_object *object);

+ 4 - 2
direct/src/plugin_npapi/startup.cxx

@@ -331,8 +331,10 @@ int16
 NPP_HandleEvent(NPP instance, void *event) {
 NPP_HandleEvent(NPP instance, void *event) {
   //  logfile << "HandleEvent\n" << flush;
   //  logfile << "HandleEvent\n" << flush;
 
 
-  // Here's a fine opportunity to check for new requests.
-  PPInstance::handle_request_loop();
+  PPInstance *inst = (PPInstance *)(instance->pdata);
+  assert(inst != NULL);
+
+  inst->handle_event(event);
 
 
   return 0;
   return 0;
 }
 }

+ 47 - 25
direct/src/showutil/runp3d.py

@@ -258,8 +258,36 @@ class AppRunner(DirectObject):
 
 
         self.startIfReady()
         self.startIfReady()
 
 
-    def setupWindow(self, windowType, x, y, width, height, parent):
-        print "setupWindow %s, %s, %s, %s, %s, %s" % (windowType, x, y, width, height, parent)
+    def clearWindowPrc(self):
+        """ Clears the windowPrc file that was created in a previous
+        call to setupWindow(), if any. """
+        
+        if self.windowPrc:
+            unloadPrcFile(self.windowPrc)
+            self.windowPrc = None
+
+    def setupWindow(self, windowType, x, y, width, height,
+                    parent, subprocessWindow):
+        """ Applies the indicated window parameters to the prc
+        settings, for future windows; or applies them directly to the
+        main window if the window has already been opened. """
+
+        print "setupWindow %s, %s, %s, %s, %s, %s, %s" % (windowType, x, y, width, height, parent, subprocessWindow)
+
+        if self.started and base.win:
+            # If we've already got a window, this must be a
+            # resize/reposition request.
+            wp = WindowProperties()
+            if x or y or windowType == 'embedded':
+                wp.setOrigin(x, y)
+            if width or height:
+                wp.setSize(width, height)
+            base.win.requestProperties(wp)
+            return
+
+        # If we haven't got a window already, start 'er up.  Apply the
+        # requested setting to the prc file.
+
         if windowType == 'hidden':
         if windowType == 'hidden':
             data = 'window-type none\n'
             data = 'window-type none\n'
         else:
         else:
@@ -271,33 +299,21 @@ class AppRunner(DirectObject):
             data += 'fullscreen 0\n'
             data += 'fullscreen 0\n'
 
 
         if windowType == 'embedded':
         if windowType == 'embedded':
-            data += 'parent-window-handle %s\n' % (parent)
+            data += 'parent-window-handle %s\nsubprocess-window %s\n' % (
+                parent, subprocessWindow)
         else:
         else:
-            data += 'parent-window-handle 0\n'
+            data += 'parent-window-handle 0\nsubprocess-window \n'
 
 
         if x or y or windowType == 'embedded':
         if x or y or windowType == 'embedded':
             data += 'win-origin %s %s\n' % (x, y)
             data += 'win-origin %s %s\n' % (x, y)
         if width or height:
         if width or height:
             data += 'win-size %s %s\n' % (width, height)
             data += 'win-size %s %s\n' % (width, height)
 
 
-        if self.windowPrc:
-            unloadPrcFile(self.windowPrc)
+        self.clearWindowPrc()
         self.windowPrc = loadPrcFileData("setupWindow", data)
         self.windowPrc = loadPrcFileData("setupWindow", data)
 
 
-        if self.started and base.win:
-            # If we've already got a window, this must be a
-            # resize/reposition request.
-            wp = WindowProperties()
-            if x or y or windowType == 'embedded':
-                wp.setOrigin(x, y)
-            if width or height:
-                wp.setSize(width, height)
-            base.win.requestProperties(wp)
-
-        else:
-            # If we haven't got a window already, start 'er up.
-            self.gotWindow = True
-            self.startIfReady()
+        self.gotWindow = True
+        self.startIfReady()
 
 
     def setRequestFunc(self, func):
     def setRequestFunc(self, func):
         """ This method is called by the plugin at startup to supply a
         """ This method is called by the plugin at startup to supply a
@@ -319,9 +335,15 @@ class AppRunner(DirectObject):
         successfully opened. """
         successfully opened. """
 
 
         if not self.windowOpened:
         if not self.windowOpened:
-            self.notifyRequest('onwindowopen')
             self.windowOpened = True
             self.windowOpened = True
 
 
+            # Now that the window is open, we don't need to keep those
+            # prc settings around any more.
+            self.clearWindowPrc()
+
+            # Inform the plugin and browser.
+            self.notifyRequest('onwindowopen')
+
     def notifyRequest(self, message):
     def notifyRequest(self, message):
         """ Delivers a notify request to the browser.  This is a "this
         """ Delivers a notify request to the browser.  This is a "this
         happened" type notification; it optionally triggers some
         happened" type notification; it optionally triggers some
@@ -340,10 +362,10 @@ class AppRunner(DirectObject):
 
 
     def evalScript(self, expression, needsResponse = False):
     def evalScript(self, expression, needsResponse = False):
         """ Evaluates an arbitrary JavaScript expression in the global
         """ Evaluates an arbitrary JavaScript expression in the global
-        DOM space.  This may be deferred if necessary if self.dom has
-        not yet been assigned.  If needsResponse is true, this waits
-        for the value and returns it, which means it may not be
-        deferred. """
+        DOM space.  This may be deferred if necessary if needsResponse
+        is False and self.dom has not yet been assigned.  If
+        needsResponse is true, this waits for the value and returns
+        it, which means it cannot be deferred. """
 
 
         if not self.dom:
         if not self.dom:
             # Defer the expression.
             # Defer the expression.