2
0
David Rose 16 жил өмнө
parent
commit
37e76f402d

+ 25 - 3
panda/src/display/Sources.pp

@@ -37,7 +37,9 @@
     stencilRenderStates.h \
     stereoDisplayRegion.I stereoDisplayRegion.h \
     displaySearchParameters.h \
-    displayInformation.h    
+    displayInformation.h \
+    subprocessWindow.h subprocessWindow.I \
+    $[if $[and $[OSX_PLATFORM],$[HAVE_P3D_PLUGIN]], subprocessWindowBuffer.h subprocessWindowBuffer.I subprocessWindowBuffer.cxx]
     
  #define INCLUDED_SOURCES  \
     standardMunger.cxx \
@@ -62,7 +64,8 @@
     stencilRenderStates.cxx \
     stereoDisplayRegion.cxx \
     displaySearchParameters.cxx \
-    displayInformation.cxx    
+    displayInformation.cxx \
+    subprocessWindow.cxx
 
   #define INSTALL_HEADERS \
     standardMunger.I standardMunger.h \
@@ -90,12 +93,31 @@
     stencilRenderStates.h \
     stereoDisplayRegion.I stereoDisplayRegion.h \
     displaySearchParameters.h \
-    displayInformation.h    
+    displayInformation.h \
+    subprocessWindow.h subprocessWindow.I \
+    subprocessWindowBuffer.h subprocessWindowBuffer.I
 
   #define IGATESCAN all
 
 #end lib_target
 
+
+#begin static_lib_target
+  // We build a static library of just these files, so the plugin can
+  // link with it in direct/src/plugin, without pulling in the rest of
+  // Panda.
+
+  #define BUILD_TARGET $[and $[OSX_PLATFORM],$[HAVE_P3D_PLUGIN]]
+
+  #define TARGET subprocbuffer
+
+  #define SOURCES \
+    subprocessWindowBuffer.h subprocessWindowBuffer.I \
+    subprocessWindowBuffer.cxx
+
+#end static_lib_target
+
+
 #begin test_bin_target
   #define TARGET test_display
   #define LOCAL_LIBS \

+ 13 - 0
panda/src/display/config_display.cxx

@@ -26,6 +26,7 @@
 #include "parasiteBuffer.h"
 #include "pandaSystem.h"
 #include "stereoDisplayRegion.h"
+#include "subprocessWindow.h"
 
 ConfigureDef(config_display);
 NotifyCategoryDef(display, "");
@@ -289,6 +290,15 @@ ConfigVariableInt parent_window_handle
           "an HWND on Windows, or the NSWindow pointer or XWindow pointer "
           "converted to an integer, on OSX and X11."));
 
+ConfigVariableFilename subprocess_window
+("subprocess-window", "",
+ PRC_DESC("The filename of a SubprocessWindowBuffer's temporary mmap file, "
+          "used for opening a window in a child process and rendering "
+          "to a different window in the parent process.  "
+          "This is specifically used for OSX when the plugin is compiled, "
+          "and is not used or needed in other environments.  See "
+          "WindowProperties::set_subprocess_window()."));
+
 ConfigVariableString framebuffer_mode
 ("framebuffer-mode", "",
  PRC_DESC("No longer has any effect.  Do not use."));
@@ -400,6 +410,9 @@ init_libdisplay() {
   ParasiteBuffer::init_type();
   StandardMunger::init_type();
   StereoDisplayRegion::init_type();
+#ifdef SUPPORT_SUBPROCESS_WINDOW
+  SubprocessWindow::init_type();
+#endif
 
 #if defined(HAVE_THREADS) && defined(DO_PIPELINING)
   PandaSystem *ps = PandaSystem::get_global_ptr();

+ 1 - 0
panda/src/display/config_display.h

@@ -73,6 +73,7 @@ extern EXPCL_PANDA_DISPLAY ConfigVariableFilename cursor_filename;
 extern EXPCL_PANDA_DISPLAY ConfigVariableEnum<WindowProperties::ZOrder> z_order;
 extern EXPCL_PANDA_DISPLAY ConfigVariableString window_title;
 extern EXPCL_PANDA_DISPLAY ConfigVariableInt parent_window_handle;
+extern EXPCL_PANDA_DISPLAY ConfigVariableFilename subprocess_window;
 
 extern EXPCL_PANDA_DISPLAY ConfigVariableString framebuffer_mode;
 extern EXPCL_PANDA_DISPLAY ConfigVariableBool framebuffer_hardware;

+ 1 - 0
panda/src/display/display_composite2.cxx

@@ -13,3 +13,4 @@
 #include "displaySearchParameters.cxx"
 #include "displayInformation.cxx"
 #include "stereoDisplayRegion.cxx"
+#include "subprocessWindow.cxx"

+ 14 - 0
panda/src/display/subprocessWindow.I

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

+ 275 - 0
panda/src/display/subprocessWindow.cxx

@@ -0,0 +1,275 @@
+// Filename: subprocessWindow.cxx
+// Created by:  drose (11Jul09)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 "subprocessWindow.h"
+
+#ifdef SUPPORT_SUBPROCESS_WINDOW
+
+#include "graphicsEngine.h"
+
+TypeHandle SubprocessWindow::_type_handle;
+
+////////////////////////////////////////////////////////////////////
+//     Function: SubprocessWindow::Constructor
+//       Access: Protected
+//  Description: Normally, the SubprocessWindow constructor is not
+//               called directly; these are created instead via the
+//               GraphicsEngine::make_window() function.
+////////////////////////////////////////////////////////////////////
+SubprocessWindow::
+SubprocessWindow(GraphicsEngine *engine, GraphicsPipe *pipe,
+                 const string &name,
+                 const FrameBufferProperties &fb_prop,
+                 const WindowProperties &win_prop,
+                 int flags,
+                 GraphicsStateGuardian *gsg,
+                 GraphicsOutput *host,
+                 const string &filename) :
+  GraphicsWindow(engine, pipe, name, fb_prop, win_prop, flags, gsg, host)
+{
+  GraphicsWindowInputDevice device =
+    GraphicsWindowInputDevice::pointer_and_keyboard(this, "keyboard/mouse");
+  _input_devices.push_back(device);
+
+  // Create a buffer with the same properties as the window.
+  flags = ((flags & ~GraphicsPipe::BF_require_window) | GraphicsPipe::BF_refuse_window);
+
+  GraphicsOutput *buffer = 
+    engine->make_output(pipe, name, 0, 
+                        fb_prop, win_prop, flags, gsg, host);
+  if (buffer != NULL) {
+    _buffer = DCAST(GraphicsBuffer, buffer);
+    // However, the buffer is not itself intended to be rendered.  We
+    // only render it indirectly, via callbacks in here.
+    _buffer->set_active(false);
+  }
+
+  // Now create a texture to receive the contents of the framebuffer
+  // from the buffer.
+  _texture = new Texture(name);
+
+  _fd = -1;
+  _mmap_size = 0;
+  _filename = filename;
+  _swbuffer = NULL;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SubprocessWindow::Destructor
+//       Access: Published, Virtual
+//  Description:
+////////////////////////////////////////////////////////////////////
+SubprocessWindow::
+~SubprocessWindow() {
+  if (_buffer != NULL) {
+    _engine->remove_window(_buffer);
+  }
+  nassertv(_swbuffer == NULL);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SubprocessWindow::process_events
+//       Access: Public, Virtual
+//  Description: Do whatever processing is necessary to ensure that
+//               the window responds to user events.  Also, honor any
+//               requests recently made via request_properties().
+//
+//               This function is called only within the window
+//               thread.
+////////////////////////////////////////////////////////////////////
+void SubprocessWindow::
+process_events() {
+  GraphicsWindow::process_events();
+
+  if (_swbuffer != NULL) {
+    SubprocessWindowBuffer::Event event;
+    while (_swbuffer->get_event(event)) {
+      // Deal with this event.  For now, we only have mouse down/up.
+      _input_devices[0].set_pointer_in_window(event._x, event._y);
+      if (event._up) {
+        _input_devices[0].button_up(MouseButton::one());
+      } else {
+        _input_devices[0].button_down(MouseButton::one());
+      }
+    }
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SubprocessWindow::begin_frame
+//       Access: Public, Virtual
+//  Description: This function will be called within the draw thread
+//               before beginning rendering for a given frame.  It
+//               should do whatever setup is required, and return true
+//               if the frame should be rendered, or false if it
+//               should be skipped.
+////////////////////////////////////////////////////////////////////
+bool SubprocessWindow::
+begin_frame(FrameMode mode, Thread *current_thread) {
+  if (_swbuffer == NULL || _buffer == NULL) {
+    return false;
+  }
+
+  if (!_swbuffer->ready_for_write()) {
+    // The other end hasn't removed a frame lately; don't bother to
+    // render.
+    Thread::force_yield();
+    return false;
+  }
+
+  bool result = _buffer->begin_frame(mode, current_thread);
+  return result;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SubprocessWindow::end_frame
+//       Access: Public, Virtual
+//  Description: This function will be called within the draw thread
+//               after rendering is completed for a given frame.  It
+//               should do whatever finalization is required.
+////////////////////////////////////////////////////////////////////
+void SubprocessWindow::
+end_frame(FrameMode mode, Thread *current_thread) {
+  _buffer->end_frame(mode, current_thread);
+
+  if (mode == FM_render) {
+    _flip_ready = true;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SubprocessWindow::begin_flip
+//       Access: Public, Virtual
+//  Description: This function will be called within the draw thread
+//               after end_frame() has been called on all windows, to
+//               initiate the exchange of the front and back buffers.
+//
+//               This should instruct the window to prepare for the
+//               flip at the next video sync, but it should not wait.
+//
+//               We have the two separate functions, begin_flip() and
+//               end_flip(), to make it easier to flip all of the
+//               windows at the same time.
+////////////////////////////////////////////////////////////////////
+void SubprocessWindow::
+begin_flip() {
+  nassertv(_buffer != (GraphicsBuffer *)NULL);
+  nassertv(_swbuffer != NULL);
+
+  RenderBuffer buffer(_gsg, DrawableRegion::get_renderbuffer_type(RTP_color));
+  buffer = _gsg->get_render_buffer(_buffer->get_draw_buffer_type(),
+                                   _buffer->get_fb_properties());
+
+  bool copied = 
+    _gsg->framebuffer_copy_to_ram(_texture, -1,
+                                  _default_display_region, buffer);
+
+  if (copied) {
+    CPTA_uchar image = _texture->get_ram_image();
+    size_t framebuffer_size = _swbuffer->get_framebuffer_size();
+    nassertv(image.size() == framebuffer_size);
+
+    // Now copy the image to our shared framebuffer.
+    void *target = _swbuffer->open_write_framebuffer();
+    memcpy(target, image.p(), framebuffer_size);
+    _swbuffer->close_write_framebuffer();
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SubprocessWindow::close_window
+//       Access: Protected, Virtual
+//  Description: Closes the window right now.  Called from the window
+//               thread.
+////////////////////////////////////////////////////////////////////
+void SubprocessWindow::
+close_window() {
+  if (_swbuffer != NULL) {
+    SubprocessWindowBuffer::close_buffer(_fd, _mmap_size, _filename, _swbuffer);
+    _fd = -1;
+    _filename = string();
+
+    _swbuffer = NULL;
+  }
+
+  if (_buffer != NULL) {
+    _buffer->request_close();
+    _buffer->process_events();
+  }
+
+  _is_valid = false;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SubprocessWindow::open_window
+//       Access: Protected, Virtual
+//  Description: Opens the window right now.  Called from the window
+//               thread.  Returns true if the window is successfully
+//               opened, or false if there was a problem.
+////////////////////////////////////////////////////////////////////
+bool SubprocessWindow::
+open_window() {
+  nout << "open_window\n";
+  
+  if (_buffer != NULL) {
+    _buffer->request_open();
+    _buffer->process_events();
+
+    _is_valid = _buffer->is_valid();
+  }
+
+  if (!_is_valid) {
+    return false;
+  }
+
+  _gsg = _buffer->get_gsg();
+
+  _swbuffer = SubprocessWindowBuffer::open_buffer(_fd, _mmap_size, _filename);
+
+  if (_swbuffer == NULL) {
+    close(_fd);
+    _fd = -1;
+    _filename = string();
+    _is_valid = false;
+    return false;
+  }
+
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SubprocessWindow::set_properties_now
+//       Access: Public, Virtual
+//  Description: Applies the requested set of properties to the
+//               window, if possible, for instance to request a change
+//               in size or minimization status.
+//
+//               The window properties are applied immediately, rather
+//               than waiting until the next frame.  This implies that
+//               this method may *only* be called from within the
+//               window thread.
+//
+//               The properties that have been applied are cleared
+//               from the structure by this function; so on return,
+//               whatever remains in the properties structure are
+//               those that were unchanged for some reason (probably
+//               because the underlying interface does not support
+//               changing that property on an open window).
+////////////////////////////////////////////////////////////////////
+void SubprocessWindow::
+set_properties_now(WindowProperties &properties) {
+  GraphicsWindow::set_properties_now(properties);
+}
+
+#endif  // SUPPORT_SUBPROCESS_WINDOW

+ 106 - 0
panda/src/display/subprocessWindow.h

@@ -0,0 +1,106 @@
+// Filename: subprocessWindow.h
+// Created by:  drose (11Jul09)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 SUBPROCESSWINDOW_H
+#define SUBPROCESSWINDOW_H
+
+#include "pandabase.h"
+
+// For now, a simple trigger whether to enable the subprocess window
+// support.  We only build it on OSX, and only when the plugin is
+// enabled; because this is (presently) the only case where it's
+// useful.
+#if defined(HAVE_P3D_PLUGIN) && defined(IS_OSX)
+#define SUPPORT_SUBPROCESS_WINDOW 1
+#else
+#undef SUPPORT_SUBPROCESS_WINDOW
+#endif
+
+#ifdef SUPPORT_SUBPROCESS_WINDOW
+
+#include "graphicsWindow.h"
+#include "graphicsBuffer.h"
+#include "texture.h"
+#include "subprocessWindowBuffer.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : SubprocessWindow
+// Description : This is a special "window" that actually renders to
+//               an offscreen buffer, copies the pixels to RAM, and
+//               then ships them to a parent process via shared memory
+//               for rendering to the window.
+//
+//               This whole nonsense is necessary because OSX doesn't
+//               allow child processes to draw to, or attach windows
+//               to, windows created in the parent process.  There's a
+//               rumor that 10.6 fixes this nonsense; this will remain
+//               to be seen.
+////////////////////////////////////////////////////////////////////
+class SubprocessWindow : public GraphicsWindow {
+public:
+  SubprocessWindow(GraphicsEngine *engine, GraphicsPipe *pipe, 
+                   const string &name,
+                   const FrameBufferProperties &fb_prop,
+                   const WindowProperties &win_prop,
+                   int flags,
+                   GraphicsStateGuardian *gsg,
+                   GraphicsOutput *host,
+                   const string &filename);
+  virtual ~SubprocessWindow();
+
+  virtual void process_events();
+
+  virtual bool begin_frame(FrameMode mode, Thread *current_thread);
+  virtual void end_frame(FrameMode mode, Thread *current_thread);
+  virtual void begin_flip();
+
+  virtual void set_properties_now(WindowProperties &properties);
+
+protected:
+  virtual void close_window();
+  virtual bool open_window();
+
+private:
+  PT(GraphicsBuffer) _buffer;
+  PT(Texture) _texture;
+
+  int _fd;
+  size_t _mmap_size;
+  string _filename;
+  SubprocessWindowBuffer *_swbuffer;
+
+public:
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    GraphicsWindow::init_type();
+    register_type(_type_handle, "SubprocessWindow",
+                  GraphicsWindow::get_class_type());
+  }
+  virtual TypeHandle get_type() const {
+    return get_class_type();
+  }
+  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
+
+private:
+  static TypeHandle _type_handle;
+};
+
+#include "subprocessWindow.I"
+
+#endif  // SUPPORT_SUBPROCESS_WINDOW
+
+#endif
+

+ 176 - 0
panda/src/display/subprocessWindowBuffer.I

@@ -0,0 +1,176 @@
+// Filename: subprocessWindowBuffer.I
+// Created by:  drose (11Jul09)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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."
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: SubprocessWindowBuffer::get_x_size
+//       Access: Public
+//  Description: Returns the width of the framebuffer in pixels.
+////////////////////////////////////////////////////////////////////
+inline int SubprocessWindowBuffer::
+get_x_size() const {
+  return _x_size;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SubprocessWindowBuffer::get_y_size
+//       Access: Public
+//  Description: Returns the height of the framebuffer in pixels.
+////////////////////////////////////////////////////////////////////
+inline int SubprocessWindowBuffer::
+get_y_size() const {
+  return _y_size;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SubprocessWindowBuffer::get_row_size
+//       Access: Public
+//  Description: Returns the length of a row of the framebuffer, in
+//               bytes.
+////////////////////////////////////////////////////////////////////
+inline size_t SubprocessWindowBuffer::
+get_row_size() const {
+  return _row_size;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SubprocessWindowBuffer::get_framebuffer_size
+//       Access: Public
+//  Description: Returns the total number of bytes in the framebuffer.
+////////////////////////////////////////////////////////////////////
+inline size_t SubprocessWindowBuffer::
+get_framebuffer_size() const {
+  return _framebuffer_size;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SubprocessWindowBuffer::ready_for_read
+//       Access: Public
+//  Description: Returns true if the framebuffer data has been updated
+//               since open_read_framebuffer() was last called.
+////////////////////////////////////////////////////////////////////
+inline bool SubprocessWindowBuffer::
+ready_for_read() const {
+  return (_last_written != _last_read);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SubprocessWindowBuffer::ready_for_write
+//       Access: Public
+//  Description: Returns true if the framebuffer data has been read
+//               since open_write_framebuffer() was last called.
+////////////////////////////////////////////////////////////////////
+inline bool SubprocessWindowBuffer::
+ready_for_write() const {
+  return (_last_written == _last_read);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SubprocessWindowBuffer::open_read_framebuffer
+//       Access: Public
+//  Description: Returns a read-only pointer to the framebuffer.  It
+//               is only valid to call this if ready_for_read() has
+//               returned true.
+//
+//               You must call close_read_framebuffer() to indicate
+//               you have finished reading.
+////////////////////////////////////////////////////////////////////
+inline const void *SubprocessWindowBuffer::
+open_read_framebuffer() {
+  assert(ready_for_read());
+  return (void *)(this + 1);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SubprocessWindowBuffer::close_read_framebuffer
+//       Access: Public
+//  Description: Releases the framebuffer after a previous call to
+//               open_read_framebuffer().
+////////////////////////////////////////////////////////////////////
+inline void SubprocessWindowBuffer::
+close_read_framebuffer() {
+  _last_read = _last_written;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SubprocessWindowBuffer::open_write_framebuffer
+//       Access: Public
+//  Description: Returns a writable pointer to the framebuffer.  It
+//               is only valid to call this if ready_for_write() has
+//               returned true.
+//
+//               You must call close_write_framebuffer() to indicate
+//               you have finished writing.
+////////////////////////////////////////////////////////////////////
+inline void *SubprocessWindowBuffer::
+open_write_framebuffer() {
+  assert(ready_for_write());
+  return (void *)(this + 1);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SubprocessWindowBuffer::close_write_framebuffer
+//       Access: Public
+//  Description: Releases the framebuffer after a previous call to
+//               open_write_framebuffer().
+////////////////////////////////////////////////////////////////////
+inline void SubprocessWindowBuffer::
+close_write_framebuffer() {
+  ++_last_written;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SubprocessWindowBuffer::add_event
+//       Access: Public
+//  Description: Adds a new Event to the queue.  Returns false
+//               if the queue was full.
+////////////////////////////////////////////////////////////////////
+inline bool SubprocessWindowBuffer::
+add_event(const SubprocessWindowBuffer::Event &event) {
+  if (((_event_in + 1) % max_events) == _event_out) {
+    // The queue is full.
+    return false;
+  }
+  _events[_event_in] = event;
+  _event_in = (_event_in + 1) % max_events;
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SubprocessWindowBuffer::has_event
+//       Access: Public
+//  Description: Returns true if the queue has at least one
+//               Event to extract, false if it is empty.
+////////////////////////////////////////////////////////////////////
+inline bool SubprocessWindowBuffer::
+has_event() const {
+  return (_event_in != _event_out);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SubprocessWindowBuffer::get_event
+//       Access: Public
+//  Description: If the queue is nonempty, fills event with the first
+//               Event on the queue and returns true.  If the queue is
+//               empty, returns false.
+////////////////////////////////////////////////////////////////////
+inline bool SubprocessWindowBuffer::
+get_event(SubprocessWindowBuffer::Event &event) {
+  if (_event_in == _event_out) {
+    return false;
+  }
+  event = _events[_event_out];
+  _event_out = (_event_out + 1) % max_events;
+  return true;
+}

+ 291 - 0
panda/src/display/subprocessWindowBuffer.cxx

@@ -0,0 +1,291 @@
+// Filename: subprocessWindowBuffer.cxx
+// Created by:  drose (11Jul09)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 "subprocessWindowBuffer.h"
+#include <sys/mman.h>
+#include <fcntl.h>
+
+#include <iostream>
+using namespace std;
+
+const char SubprocessWindowBuffer::
+_magic_number[SubprocessWindowBuffer::magic_number_length] = "pNdaSWB";
+
+////////////////////////////////////////////////////////////////////
+//     Function: SubprocessWindowBuffer::operator new
+//       Access: Private
+//  Description: Placement operator.  Returns addr, a trivial
+//               pass-through.
+////////////////////////////////////////////////////////////////////
+void *SubprocessWindowBuffer::
+operator new(size_t, void *addr) {
+  cerr << "operator new: " << addr << "\n";
+  return addr;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SubprocessWindowBuffer::Constructor
+//       Access: Private
+//  Description: This constructor is private; it is not intended to be
+//               called directly.  It is used in make_buffer() to
+//               create a temporary local object, to determine the
+//               required mmap_size for a given window size.
+////////////////////////////////////////////////////////////////////
+SubprocessWindowBuffer::
+SubprocessWindowBuffer(int x_size, int y_size) {
+  cerr << "Constructing " << this << "\n";
+  memcpy(_this_magic, _magic_number, magic_number_length);
+  _x_size = x_size;
+  _y_size = y_size;
+  _row_size = _x_size * 4;
+  _framebuffer_size = _row_size * y_size;
+  _event_in = 0;
+  _event_out = 0;
+  _last_written = 0;
+  _last_read = 0;
+
+  _mmap_size = sizeof(*this) + _framebuffer_size;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SubprocessWindowBuffer::Copy Constructor
+//       Access: Private
+//  Description: 
+////////////////////////////////////////////////////////////////////
+SubprocessWindowBuffer::
+SubprocessWindowBuffer(const SubprocessWindowBuffer &copy) :
+  _x_size(copy._x_size),
+  _y_size(copy._y_size),
+  _row_size(copy._row_size),
+  _framebuffer_size(copy._framebuffer_size),
+  _mmap_size(copy._mmap_size)
+{
+  memcpy(_this_magic, _magic_number, magic_number_length);
+  _event_in = 0;
+  _event_out = 0;
+  _last_written = 0;
+  _last_read = 0;
+  cerr << "Copy Constructing " << this << "\n";
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SubprocessWindowBuffer::Destructor
+//       Access: Private
+//  Description: 
+////////////////////////////////////////////////////////////////////
+SubprocessWindowBuffer::
+~SubprocessWindowBuffer() {
+  cerr << "Destructing " << this << "\n";
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SubprocessWindowBuffer::new_buffer
+//       Access: Public, Static
+//  Description: Call this method to create a new buffer in shared
+//               memory space.  Supply the desired size of the window.
+//
+//               This method will create the required shared-memory
+//               buffer and return a SubprocessWindowBuffer allocated
+//               within that shared memory, or NULL if there is a
+//               failure allocating sufficient shared memory.
+//
+//               It also creates a temporary file on disk and returns
+//               fd, mmap_size, and filename, which the caller must
+//               retain and eventually pass to destroy_buffer().  The
+//               filename should be passed to the child process to
+//               open with open_buffer().
+////////////////////////////////////////////////////////////////////
+SubprocessWindowBuffer *SubprocessWindowBuffer::
+new_buffer(int &fd, size_t &mmap_size, string &filename,
+           int x_size, int y_size) {
+  mmap_size = 0;
+  fd = -1;
+
+  filename = tmpnam(NULL);
+  cerr << "new_buffer: " << filename << "\n";
+
+  fd = open(filename.c_str(), O_RDWR | O_CREAT | O_EXCL, 0600);
+  if (fd == -1) {
+    perror(filename.c_str());
+    return NULL;
+  }
+
+  // Create a temporary object to determine the required size.
+  SubprocessWindowBuffer temp(x_size, y_size);
+  mmap_size = temp._mmap_size;
+
+  // Ensure the disk file is large enough.
+  size_t zero_size = 1024;
+  char zero[zero_size];
+  memset(zero, 0, zero_size);
+  for (size_t bi = 0; bi < mmap_size; bi += zero_size) {
+    write(fd, zero, zero_size);
+  }
+
+  cerr << "size = " << x_size << " * " << y_size << " = " 
+       << mmap_size << " bytes\n";
+
+  void *shared_mem = mmap(NULL, mmap_size, PROT_READ | PROT_WRITE,
+                          MAP_SHARED, fd, 0);
+  if (shared_mem == (void *)-1) {
+    // Failure to map.
+    close(fd);
+    fd = -1;
+    mmap_size = 0;
+    return NULL;
+  }
+
+  cerr << "shared_mem = " << shared_mem << "\n";
+
+  // Now create the actual object in the shared-memory buffer.
+  return new(shared_mem) SubprocessWindowBuffer(temp);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SubprocessWindowBuffer::destroy_buffer
+//       Access: Public, Static
+//  Description: Destroys a buffer object created via a previous call
+//               to new_buffer().  This destructs objects within the
+//               buffer, unmaps the shared memory, and closes the file
+//               descriptor.
+////////////////////////////////////////////////////////////////////
+void SubprocessWindowBuffer::
+destroy_buffer(int fd, size_t mmap_size, const string &filename,
+               SubprocessWindowBuffer *buffer) {
+  buffer->~SubprocessWindowBuffer();
+  close_buffer(fd, mmap_size, filename, buffer);
+
+  // This isn't really necessary, since our child process should have
+  // unlinked it; but we do it anyway just for good measure (for
+  // instance, in case the child process never got started).  I
+  // suppose there is some risk that we will accidentally delete
+  // someone else's file this way, but the risk is small.
+  unlink(filename.c_str());
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SubprocessWindowBuffer::open_buffer
+//       Access: Public, Static
+//  Description: Call this method to open a reference to an existing
+//               buffer in shared memory space.  Supply the temporary
+//               filename returned by new_buffer(), above (presumably
+//               from the parent process).
+//
+//               This method will mmap the required shared-memory
+//               buffer and return a SubprocessWindowBuffer allocated
+//               within that shared memory, or NULL if there is some
+//               failure.  The caller must retain fd, mmap_size, and
+//               filename and eventually pass all three to
+//               close_buffer().
+////////////////////////////////////////////////////////////////////
+SubprocessWindowBuffer *SubprocessWindowBuffer::
+open_buffer(int &fd, size_t &mmap_size, const string &filename) {
+  cerr << "open_buffer: " << filename << "\n";
+
+  mmap_size = 0;
+
+  fd = open(filename.c_str(), O_RDWR);
+  if (fd == -1) {
+    perror(filename.c_str());
+    return NULL;
+  }
+
+  // Check that the disk file is large enough.
+  off_t file_size = lseek(fd, 0, SEEK_END);
+  if (file_size < sizeof(SubprocessWindowBuffer)) {
+    cerr << filename << " not large enough.\n";
+    close(fd);
+    fd = -1;
+    return NULL;
+  }
+
+  // First, map enough memory to read the buffer object.
+  size_t initial_size = sizeof(SubprocessWindowBuffer);
+  void *shared_mem = mmap(NULL, initial_size, PROT_READ,
+                          MAP_SHARED, fd, 0);
+  if (shared_mem == (void *)-1) {
+    perror("mmap");
+    cerr << "Couldn't map.\n";
+    close(fd);
+    fd = -1;
+    return NULL;
+  }
+
+  SubprocessWindowBuffer *temp = (SubprocessWindowBuffer *)shared_mem;
+  if (!temp->verify_magic_number()) {
+    cerr << "Not a subprocess window buffer: " << filename << "\n";
+    munmap(shared_mem, initial_size);
+    close(fd);
+    fd = -1;
+    return NULL;
+  }
+    
+
+  mmap_size = temp->_mmap_size;
+
+  // Now unmap that and remap the proper-size buffer.
+  munmap(shared_mem, initial_size);
+
+  if (file_size < mmap_size) {
+    cerr << filename << " not large enough.\n";
+    close(fd);
+    fd = -1;
+    return NULL;
+  }
+
+  shared_mem = mmap(NULL, mmap_size, PROT_READ | PROT_WRITE,
+                    MAP_SHARED, fd, 0);
+  if (shared_mem == (void *)-1) {
+    perror("mmap");
+    cerr << "Couldn't map 2.\n";
+    return NULL;
+  }
+
+  // Now that we've successfully opened and mapped the file, we can
+  // safely delete it from the file system.
+  unlink(filename.c_str());
+
+  SubprocessWindowBuffer *buffer = (SubprocessWindowBuffer *)shared_mem;
+  assert(buffer->_mmap_size == mmap_size);
+  return buffer;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SubprocessWindowBuffer::close_buffer
+//       Access: Public, Static
+//  Description: Closes a buffer object created via a previous call
+//               to open_buffer().  This unmaps the shared memory
+//               and closes the file descriptor, but does not molest
+//               the shared buffer itself.
+////////////////////////////////////////////////////////////////////
+void SubprocessWindowBuffer::
+close_buffer(int fd, size_t mmap_size, const string &filename,
+             SubprocessWindowBuffer *buffer) {
+  munmap((void *)buffer, mmap_size);
+  close(fd);
+
+  // Guess we shouldn't unlink() the file here, since we already did
+  // in open_buffer().
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SubprocessWindowBuffer::verify_magic_number
+//       Access: Public
+//  Description: Returns true if the buffer's magic number matches,
+//               false otherwise.
+////////////////////////////////////////////////////////////////////
+bool SubprocessWindowBuffer::
+verify_magic_number() const {
+  return (memcmp(_this_magic, _magic_number, magic_number_length) == 0);
+}

+ 124 - 0
panda/src/display/subprocessWindowBuffer.h

@@ -0,0 +1,124 @@
+// Filename: subprocessWindowBuffer.h
+// Created by:  drose (11Jul09)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 SUBPROCESSWINDOWBUFFER_H
+#define SUBPROCESSWINDOWBUFFER_H
+
+#include <stdio.h>  // perror
+#include <assert.h>
+#include <string>
+using namespace std;
+
+////////////////////////////////////////////////////////////////////
+//       Class : SubprocessWindowBuffer
+// Description : This is a special class that is designed to faciliate
+//               SubprocessWindow.  It's intended to be allocated
+//               within a shared memory buffer, and it contains space
+//               for a framebuffer image to be stored for transferring
+//               between processes, as well as appropriate
+//               synchronization primitives.
+//
+//               It's designed to be compiled outside of Panda, so
+//               that code that doesn't link with Panda (in
+//               particular, the Panda3D plugin core API) may still
+//               link with this and use it.
+//
+//               At the moment, and maybe indefinitely, it is only
+//               compiled on OSX, and only when we are building
+//               support for the plugin; because it is only needed
+//               then.
+////////////////////////////////////////////////////////////////////
+class SubprocessWindowBuffer {
+private:
+  void *operator new(size_t, void *addr);
+  SubprocessWindowBuffer(int x_size, int y_size);
+  SubprocessWindowBuffer(const SubprocessWindowBuffer &copy);
+  ~SubprocessWindowBuffer();
+
+public:
+  static SubprocessWindowBuffer *new_buffer(int &fd, size_t &mmap_size,
+                                            string &filename,
+                                            int x_size, int y_size);
+  static void destroy_buffer(int fd, size_t mmap_size, 
+                             const string &filename,
+                             SubprocessWindowBuffer *buffer);
+
+  static SubprocessWindowBuffer *open_buffer(int &fd, size_t &mmap_size,
+                                             const string &filename);
+  static void close_buffer(int fd, size_t mmap_size,
+                           const string &filename,
+                           SubprocessWindowBuffer *buffer);
+
+  bool verify_magic_number() const;
+
+  inline int get_x_size() const;
+  inline int get_y_size() const;
+  inline size_t get_row_size() const;
+  inline size_t get_framebuffer_size() const;
+
+  inline bool ready_for_read() const;
+  inline bool ready_for_write() const;
+
+  inline const void *open_read_framebuffer();
+  inline void close_read_framebuffer();
+  inline void *open_write_framebuffer();
+  inline void close_write_framebuffer();
+
+  class Event {
+  public:
+    // int _key;  TODO.
+    bool _up;
+    int _x, _y;  // position of mouse at the time of the event
+  };
+
+  inline bool add_event(const Event &event);
+  inline bool has_event() const;
+  inline bool get_event(Event &event);
+
+private:
+  // The first thing we store in the buffer is a magic number, so we
+  // don't accidentally memory-map the wrong file and attempt to treat
+  // it as a window buffer.
+  enum { magic_number_length = 8 };
+  static const char _magic_number[magic_number_length];
+  char _this_magic[magic_number_length];
+
+  // Then we have the required size of the entire structure, including
+  // its data blocks.
+  size_t _mmap_size;
+
+  // Then some other important parameters.
+  int _x_size, _y_size;
+  size_t _row_size;
+  size_t _framebuffer_size;
+
+  // A circular queue of events.
+  enum { max_events = 64 };
+  int _event_in;  // next slot to write an event to
+  int _event_out; // next slot to read an event from
+  Event _events[max_events];
+  // The queue is empty when _event_in == _event_out.
+  // It is full when _event_in == _event_out - 1, circularly.
+
+  // These sequence numbers are incremented as frames are written and
+  // read.
+  int _last_written;
+  int _last_read;
+
+  // The framebuffer data begins immediately at the end of this class.
+};
+
+#include "subprocessWindowBuffer.I"
+
+#endif

+ 97 - 7
panda/src/display/windowProperties.I

@@ -749,7 +749,18 @@ clear_z_order() {
 ////////////////////////////////////////////////////////////////////
 //     Function: WindowProperties::set_mouse_mode
 //       Access: Published
-//  Description: Removes the z_order specification from the properties.
+//  Description: Specifies the mode in which the window is to operate
+//               its mouse pointer.  The default is M_absolute, which
+//               is the normal mode in which a mouse pointer operates;
+//               but you can also set M_relative, which is
+//               particularly useful for FPS-style mouse movements
+//               where you have hidden the mouse pointer and are are
+//               more interested in how fast the mouse is moving,
+//               rather than precisely where the pointer is hovering.
+//
+//               This has no effect on Windows and Linux, which do not
+//               have this concept; but is important to do on OSX to
+//               properly enable a smooth FPS-style mouselook mode.
 ////////////////////////////////////////////////////////////////////
 INLINE void WindowProperties::
 set_mouse_mode(MouseMode mode) {
@@ -760,7 +771,7 @@ set_mouse_mode(MouseMode mode) {
 ////////////////////////////////////////////////////////////////////
 //     Function: WindowProperties::get_mouse_mode
 //       Access: Published
-//  Description: Removes the z_order specification from the properties.
+//  Description: See set_mouse_mode().
 ////////////////////////////////////////////////////////////////////
 INLINE WindowProperties::MouseMode WindowProperties::
 get_mouse_mode() const {
@@ -768,9 +779,9 @@ get_mouse_mode() const {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: WindowProperties::has_moude_mode
+//     Function: WindowProperties::has_mouse_mode
 //       Access: Published
-//  Description: Removes the z_order specification from the properties.
+//  Description: 
 ////////////////////////////////////////////////////////////////////
 INLINE bool WindowProperties::
 has_mouse_mode() const {
@@ -780,7 +791,7 @@ has_mouse_mode() const {
 ////////////////////////////////////////////////////////////////////
 //     Function: WindowProperties::clear_mouse_mode
 //       Access: Published
-//  Description: Removes the z_order specification from the properties.
+//  Description: Removes the mouse_mode specification from the properties.
 ////////////////////////////////////////////////////////////////////
 INLINE void WindowProperties::
 clear_mouse_mode() {
@@ -791,7 +802,22 @@ clear_mouse_mode() {
 ////////////////////////////////////////////////////////////////////
 //     Function: WindowProperties::set_parent_window
 //       Access: Published
-//  Description: Removes the z_order specification from the properties.
+//  Description: Specifies the window that this window should be
+//               attached to.  If this is zero or unspecified, the
+//               window will be created as a toplevel window on the
+//               desktop; if this is nonzero, the window will be bound
+//               as a child window to the indicated parent window.
+//
+//               The actual value for "parent" is platform-specific.
+//               On Windows, it is the HWND of the parent window, cast
+//               to an unsigned integer.  On X11, it is the Window
+//               pointer of the parent window, similarly cast (yes,
+//               it's a portability issue).
+//
+//               On OSX, this is the NSWindow pointer, though there
+//               appear to be some compatibility issues (OSX doesn't
+//               easily support the parent-window model).  On OSX,
+//               consider using subprocess_window instead.
 ////////////////////////////////////////////////////////////////////
 INLINE void WindowProperties::
 set_parent_window(size_t parent) {
@@ -802,7 +828,7 @@ set_parent_window(size_t parent) {
 ////////////////////////////////////////////////////////////////////
 //     Function: WindowProperties::get_parent_window
 //       Access: Published
-//  Description: Removes the parent Window 
+//  Description: Returns the parent window specification.
 ////////////////////////////////////////////////////////////////////
 INLINE size_t WindowProperties::
 get_parent_window() const {
@@ -830,6 +856,70 @@ clear_parent_window() {
   _parent_window = (size_t)NULL;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: WindowProperties::set_subprocess_window
+//       Access: Published
+//  Description: Specifies that the window should be created as a
+//               "subprocess window", which is a special concept
+//               needed on OSX, to support windows that may run in a
+//               subprocess and communicate the output of their
+//               rendering to a parent process.
+//
+//               To use it, create a SubprocessWindowBuffer in the
+//               parent process, pass the resulting temporary filename
+//               to the child process, and set that filename here
+//               before opening a window.  Panda will open a
+//               SubprocessWindow instead of a normal window; and that
+//               class will take the output of the rendering and write
+//               it to the SubprocessWindowBuffer for the parent
+//               process to extract.
+//
+//               This is particularly useful for implementing the web
+//               browser plugin on OSX, which requires exactly this
+//               sort of process isolation in order to render to the
+//               browser page.
+//
+//               This feature is not currently available on other
+//               platforms (and they have no need of it).
+////////////////////////////////////////////////////////////////////
+INLINE void WindowProperties::
+set_subprocess_window(const Filename &filename) {
+  _subprocess_window = filename;
+  _specified |= S_subprocess_window;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: WindowProperties::get_subprocess_window
+//       Access: Published
+//  Description: Returns the filename specified to set_subprocess_window().
+////////////////////////////////////////////////////////////////////
+INLINE const Filename &WindowProperties::
+get_subprocess_window() const {
+ return _subprocess_window;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: WindowProperties::has_subprocess_window
+//       Access: Published
+//  Description: Returns true if set_subprocess_window() was set.
+////////////////////////////////////////////////////////////////////
+INLINE bool WindowProperties::
+has_subprocess_window() const {
+  return ((_specified & S_subprocess_window) != 0);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: WindowProperties::clear_subprocess_window
+//       Access: Published
+//  Description: Removes the subprocess_window specification from the
+//               properties.
+////////////////////////////////////////////////////////////////////
+INLINE void WindowProperties::
+clear_subprocess_window() {
+  _specified &= ~S_subprocess_window;
+  _subprocess_window = Filename();
+}
+
 
 INLINE ostream &
 operator << (ostream &out, const WindowProperties &properties) {

+ 14 - 5
panda/src/display/windowProperties.cxx

@@ -45,6 +45,7 @@ operator = (const WindowProperties &copy) {
   _flags = copy._flags;
   _mouse_mode = copy._mouse_mode;
   _parent_window = copy._parent_window;
+  _subprocess_window = copy._subprocess_window;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -86,7 +87,11 @@ get_default() {
   if (parent_window_handle.get_value() != 0) {
     props.set_parent_window(parent_window_handle);
   }
+  if (subprocess_window.has_value()) {
+    props.set_subprocess_window(subprocess_window);
+  }
   props.set_mouse_mode(M_absolute);
+
   return props;
 }
 
@@ -122,8 +127,8 @@ operator == (const WindowProperties &other) const {
           _icon_filename == other._icon_filename &&
           _cursor_filename == other._cursor_filename &&
           _mouse_mode == other._mouse_mode &&
-          _parent_window == other._parent_window);
-  
+          _parent_window == other._parent_window &&
+          _subprocess_window == other._subprocess_window);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -147,6 +152,7 @@ clear() {
   _flags = 0;
   _mouse_mode = M_absolute;
   _parent_window = 0;
+  _subprocess_window = Filename();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -200,15 +206,15 @@ add_properties(const WindowProperties &other) {
   if (other.has_z_order()) {
     set_z_order(other.get_z_order());
   }
-
   if (other.has_mouse_mode()) {
     set_mouse_mode(other.get_mouse_mode());
   }
-
   if (other.has_parent_window()) {
     set_parent_window(other.get_parent_window());
   }
-
+  if (other.has_subprocess_window()) {
+    set_subprocess_window(other.get_subprocess_window());
+  }
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -268,6 +274,9 @@ output(ostream &out) const {
   if (has_parent_window()) {
     out << "parent:" << get_parent_window() << " ";
   }
+  if (has_subprocess_window()) {
+    out << "subprocess_window:" << get_subprocess_window() << " ";
+  }
 
 }
 

+ 26 - 22
panda/src/display/windowProperties.h

@@ -28,8 +28,6 @@
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDA_DISPLAY WindowProperties {
 PUBLISHED:
-
-
   enum ZOrder {
     Z_bottom,
     Z_normal,
@@ -132,12 +130,16 @@ PUBLISHED:
   INLINE bool has_z_order() const;
   INLINE void clear_z_order();
 
-
   INLINE void set_parent_window(size_t parent);
-  INLINE size_t  get_parent_window() const;
+  INLINE size_t get_parent_window() const;
   INLINE bool has_parent_window() const;
   INLINE void clear_parent_window();
 
+  INLINE void set_subprocess_window(const Filename &filename);
+  INLINE const Filename &get_subprocess_window() const;
+  INLINE bool has_subprocess_window() const;
+  INLINE void clear_subprocess_window();
+
   void add_properties(const WindowProperties &other);
 
   void output(ostream &out) const;
@@ -147,22 +149,23 @@ private:
   // structure have been filled in by the user, and which remain
   // unspecified.
   enum Specified {
-    S_origin           = 0x0001,
-    S_size             = 0x0002,
-    S_title            = 0x0004,
-    S_undecorated      = 0x0008,
-    S_fullscreen       = 0x0010,
-    S_foreground       = 0x0020,
-    S_minimized        = 0x0040,
-    S_open             = 0x0080,
-    S_cursor_hidden    = 0x0100,
-    S_fixed_size       = 0x0200,
-    S_z_order          = 0x0400,
-    S_icon_filename    = 0x0800,
-    S_cursor_filename  = 0x1000,
-    S_mouse_mode       = 0x2000,
-    S_parent_window    = 0x4000,
-    S_raw_mice         = 0x8000,
+    S_origin               = 0x00001,
+    S_size                 = 0x00002,
+    S_title                = 0x00004,
+    S_undecorated          = 0x00008,
+    S_fullscreen           = 0x00010,
+    S_foreground           = 0x00020,
+    S_minimized            = 0x00040,
+    S_open                 = 0x00080,
+    S_cursor_hidden        = 0x00100,
+    S_fixed_size           = 0x00200,
+    S_z_order              = 0x00400,
+    S_icon_filename        = 0x00800,
+    S_cursor_filename      = 0x01000,
+    S_mouse_mode           = 0x02000,
+    S_parent_window        = 0x04000,
+    S_raw_mice             = 0x08000,
+    S_subprocess_window    = 0x10000,
   };
 
   // This bitmask represents the true/false settings for various
@@ -189,8 +192,9 @@ private:
   Filename _cursor_filename;
   Filename _icon_filename;
   ZOrder _z_order;
-  int _flags;
-  size_t _parent_window;  // a HWND or WindowRef or .. what ever it is on X win...
+  unsigned int _flags;
+  size_t _parent_window;  // a HWND or WindowRef or ..
+  Filename _subprocess_window;
 };
 
 EXPCL_PANDA_DISPLAY ostream &

+ 10 - 1
panda/src/osxdisplay/osxGraphicsPipe.cxx

@@ -15,6 +15,8 @@
 #include "osxGraphicsBuffer.h"
 #include "osxGraphicsStateGuardian.h"
 #include "pnmImage.h"
+#include "subprocessWindow.h"
+
 
 
 TypeHandle osxGraphicsPipe::_type_handle;
@@ -221,7 +223,7 @@ make_output(const string &name,
     DCAST_INTO_R(osxgsg, gsg, NULL);
   }
   
-  // First thing to try: a osxGraphicsWindow
+  // First thing to try: an osxGraphicsWindow
 
   if (retry == 0) {
     if (((flags&BF_require_parasite)!=0)||
@@ -232,6 +234,13 @@ make_output(const string &name,
         ((flags&BF_can_bind_every)!=0)) {
       return NULL;
     }
+#ifdef SUPPORT_SUBPROCESS_WINDOW
+    if (win_prop.has_subprocess_window()) {
+      return new SubprocessWindow(engine, this, name, fb_prop, win_prop,
+                                  flags, gsg, host,
+                                  win_prop.get_subprocess_window().to_os_specific());
+    }
+#endif  // SUPPORT_SUBPROCESS_WINDOW
     return new osxGraphicsWindow(engine, this, name, fb_prop, win_prop,
                                  flags, gsg, host);
   }

+ 3 - 3
panda/src/pipeline/Sources.pp

@@ -60,7 +60,7 @@
     reMutex.I reMutex.h \
     reMutexDirect.h reMutexDirect.I \
     reMutexHolder.I reMutexHolder.h \
-    semaphore.h semaphore.I \
+    psemaphore.h psemaphore.I \
     thread.h thread.I threadImpl.h \
     threadDummyImpl.h threadDummyImpl.I \
     threadPosixImpl.h threadPosixImpl.I \
@@ -113,7 +113,7 @@
     reMutex.cxx \
     reMutexDirect.cxx \
     reMutexHolder.cxx \
-    semaphore.cxx \
+    psemaphore.cxx \
     thread.cxx \
     threadDummyImpl.cxx \
     threadPosixImpl.cxx \
@@ -172,7 +172,7 @@
     reMutex.I reMutex.h \
     reMutexDirect.h reMutexDirect.I \
     reMutexHolder.I reMutexHolder.h \
-    semaphore.h semaphore.I \
+    psemaphore.h psemaphore.I \
     thread.h thread.I threadImpl.h \
     threadDummyImpl.h threadDummyImpl.I \
     threadPosixImpl.h threadPosixImpl.I \

+ 1 - 1
panda/src/pipeline/pipeline_composite2.cxx

@@ -9,11 +9,11 @@
 #include "pipelineCyclerTrivialImpl.cxx"
 #include "pipelineCyclerTrueImpl.cxx"
 #include "pmutex.cxx"
+#include "psemaphore.cxx"
 #include "pythonThread.cxx"
 #include "reMutex.cxx"
 #include "reMutexDirect.cxx"
 #include "reMutexHolder.cxx"
-#include "semaphore.cxx"
 #include "thread.cxx"
 #include "threadDummyImpl.cxx"
 #include "threadPosixImpl.cxx"

+ 1 - 1
panda/src/pipeline/semaphore.I → panda/src/pipeline/psemaphore.I

@@ -1,4 +1,4 @@
-// Filename: semaphore.I
+// Filename: psemaphore.I
 // Created by:  drose (13Oct08)
 //
 ////////////////////////////////////////////////////////////////////

+ 2 - 2
panda/src/pipeline/semaphore.cxx → panda/src/pipeline/psemaphore.cxx

@@ -1,4 +1,4 @@
-// Filename: semaphore.cxx
+// Filename: psemaphore.cxx
 // Created by:  drose (13Oct08)
 //
 ////////////////////////////////////////////////////////////////////
@@ -12,7 +12,7 @@
 //
 ////////////////////////////////////////////////////////////////////
 
-#include "semaphore.h"
+#include "psemaphore.h"
 
 ////////////////////////////////////////////////////////////////////
 //     Function: Semaphore::output

+ 4 - 4
panda/src/pipeline/semaphore.h → panda/src/pipeline/psemaphore.h

@@ -1,4 +1,4 @@
-// Filename: semaphore.h
+// Filename: psemaphore.h
 // Created by:  drose (13Oct08)
 //
 ////////////////////////////////////////////////////////////////////
@@ -12,8 +12,8 @@
 //
 ////////////////////////////////////////////////////////////////////
 
-#ifndef SEMAPHORE_H
-#define SEMAPHORE_H
+#ifndef PSEMAPHORE_H
+#define PSEMAPHORE_H
 
 #include "pandabase.h"
 #include "pmutex.h"
@@ -58,6 +58,6 @@ operator << (ostream &out, const Semaphore &sem) {
   return out;
 }
 
-#include "semaphore.I"
+#include "psemaphore.I"
 
 #endif

+ 8 - 0
panda/src/tinydisplay/tinyOsxGraphicsPipe.cxx

@@ -21,6 +21,7 @@
 #include "tinyOsxGraphicsWindow.h"
 #include "tinyGraphicsBuffer.h"
 #include "pnmImage.h"
+#include "subprocessWindow.h"
 
 TypeHandle TinyOsxGraphicsPipe::_type_handle;
   
@@ -234,6 +235,13 @@ make_output(const string &name,
         return NULL;
       }
     }
+#ifdef SUPPORT_SUBPROCESS_WINDOW
+    if (win_prop.has_subprocess_window()) {
+      return new SubprocessWindow(engine, this, name, fb_prop, win_prop,
+                                  flags, gsg, host,
+                                  win_prop.get_subprocess_window().to_os_specific());
+    }
+#endif  // SUPPORT_SUBPROCESS_WINDOW
     return new TinyOsxGraphicsWindow(engine, this, name, fb_prop, win_prop,
                                      flags, gsg, host);
   }