From 37e76f402dd9d779e56a696f21cde2bc9fbe58d2 Mon Sep 17 00:00:00 2001 From: David Rose Date: Mon, 13 Jul 2009 07:14:01 +0000 Subject: [PATCH] subprocess window --- panda/src/display/Sources.pp | 28 +- panda/src/display/config_display.cxx | 13 + panda/src/display/config_display.h | 1 + panda/src/display/display_composite2.cxx | 1 + panda/src/display/subprocessWindow.I | 14 + panda/src/display/subprocessWindow.cxx | 275 +++++++++++++++++ panda/src/display/subprocessWindow.h | 106 +++++++ panda/src/display/subprocessWindowBuffer.I | 176 +++++++++++ panda/src/display/subprocessWindowBuffer.cxx | 291 ++++++++++++++++++ panda/src/display/subprocessWindowBuffer.h | 124 ++++++++ panda/src/display/windowProperties.I | 104 ++++++- panda/src/display/windowProperties.cxx | 19 +- panda/src/display/windowProperties.h | 48 +-- panda/src/osxdisplay/osxGraphicsPipe.cxx | 11 +- panda/src/pipeline/Sources.pp | 6 +- panda/src/pipeline/pipeline_composite2.cxx | 2 +- .../pipeline/{semaphore.I => psemaphore.I} | 2 +- .../{semaphore.cxx => psemaphore.cxx} | 4 +- .../pipeline/{semaphore.h => psemaphore.h} | 8 +- panda/src/tinydisplay/tinyOsxGraphicsPipe.cxx | 8 + 20 files changed, 1192 insertions(+), 49 deletions(-) create mode 100644 panda/src/display/subprocessWindow.I create mode 100644 panda/src/display/subprocessWindow.cxx create mode 100644 panda/src/display/subprocessWindow.h create mode 100644 panda/src/display/subprocessWindowBuffer.I create mode 100644 panda/src/display/subprocessWindowBuffer.cxx create mode 100644 panda/src/display/subprocessWindowBuffer.h rename panda/src/pipeline/{semaphore.I => psemaphore.I} (99%) rename panda/src/pipeline/{semaphore.cxx => psemaphore.cxx} (93%) rename panda/src/pipeline/{semaphore.h => psemaphore.h} (94%) diff --git a/panda/src/display/Sources.pp b/panda/src/display/Sources.pp index 5c12758ec1..c0ce1012bd 100644 --- a/panda/src/display/Sources.pp +++ b/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 \ diff --git a/panda/src/display/config_display.cxx b/panda/src/display/config_display.cxx index 25161b5155..5c260c98f8 100644 --- a/panda/src/display/config_display.cxx +++ b/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(); diff --git a/panda/src/display/config_display.h b/panda/src/display/config_display.h index 8f8d302773..38c9427cde 100644 --- a/panda/src/display/config_display.h +++ b/panda/src/display/config_display.h @@ -73,6 +73,7 @@ extern EXPCL_PANDA_DISPLAY ConfigVariableFilename cursor_filename; extern EXPCL_PANDA_DISPLAY ConfigVariableEnum 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; diff --git a/panda/src/display/display_composite2.cxx b/panda/src/display/display_composite2.cxx index 1d9152995a..43bcfd7219 100644 --- a/panda/src/display/display_composite2.cxx +++ b/panda/src/display/display_composite2.cxx @@ -13,3 +13,4 @@ #include "displaySearchParameters.cxx" #include "displayInformation.cxx" #include "stereoDisplayRegion.cxx" +#include "subprocessWindow.cxx" diff --git a/panda/src/display/subprocessWindow.I b/panda/src/display/subprocessWindow.I new file mode 100644 index 0000000000..a7cff61c4e --- /dev/null +++ b/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." +// +//////////////////////////////////////////////////////////////////// + diff --git a/panda/src/display/subprocessWindow.cxx b/panda/src/display/subprocessWindow.cxx new file mode 100644 index 0000000000..5f60df305b --- /dev/null +++ b/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 diff --git a/panda/src/display/subprocessWindow.h b/panda/src/display/subprocessWindow.h new file mode 100644 index 0000000000..bc2accce02 --- /dev/null +++ b/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 + diff --git a/panda/src/display/subprocessWindowBuffer.I b/panda/src/display/subprocessWindowBuffer.I new file mode 100644 index 0000000000..289f8712df --- /dev/null +++ b/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; +} diff --git a/panda/src/display/subprocessWindowBuffer.cxx b/panda/src/display/subprocessWindowBuffer.cxx new file mode 100644 index 0000000000..96d4b33b77 --- /dev/null +++ b/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 +#include + +#include +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 ©) : + _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); +} diff --git a/panda/src/display/subprocessWindowBuffer.h b/panda/src/display/subprocessWindowBuffer.h new file mode 100644 index 0000000000..721f86e652 --- /dev/null +++ b/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 // perror +#include +#include +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 ©); + ~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 diff --git a/panda/src/display/windowProperties.I b/panda/src/display/windowProperties.I index ab020c1154..c338253326 100644 --- a/panda/src/display/windowProperties.I +++ b/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) { diff --git a/panda/src/display/windowProperties.cxx b/panda/src/display/windowProperties.cxx index b9b5b107eb..9a51597de6 100644 --- a/panda/src/display/windowProperties.cxx +++ b/panda/src/display/windowProperties.cxx @@ -45,6 +45,7 @@ operator = (const WindowProperties ©) { _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() << " "; + } } diff --git a/panda/src/display/windowProperties.h b/panda/src/display/windowProperties.h index f9c0c052c0..f2f6d52ce8 100644 --- a/panda/src/display/windowProperties.h +++ b/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 & diff --git a/panda/src/osxdisplay/osxGraphicsPipe.cxx b/panda/src/osxdisplay/osxGraphicsPipe.cxx index d071933c92..f08d430de7 100644 --- a/panda/src/osxdisplay/osxGraphicsPipe.cxx +++ b/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); } diff --git a/panda/src/pipeline/Sources.pp b/panda/src/pipeline/Sources.pp index 6f2b1e2d47..386288cdcf 100644 --- a/panda/src/pipeline/Sources.pp +++ b/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 \ diff --git a/panda/src/pipeline/pipeline_composite2.cxx b/panda/src/pipeline/pipeline_composite2.cxx index 4197627925..e5ee007a77 100644 --- a/panda/src/pipeline/pipeline_composite2.cxx +++ b/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" diff --git a/panda/src/pipeline/semaphore.I b/panda/src/pipeline/psemaphore.I similarity index 99% rename from panda/src/pipeline/semaphore.I rename to panda/src/pipeline/psemaphore.I index 883fbb4096..783838b1fc 100644 --- a/panda/src/pipeline/semaphore.I +++ b/panda/src/pipeline/psemaphore.I @@ -1,4 +1,4 @@ -// Filename: semaphore.I +// Filename: psemaphore.I // Created by: drose (13Oct08) // //////////////////////////////////////////////////////////////////// diff --git a/panda/src/pipeline/semaphore.cxx b/panda/src/pipeline/psemaphore.cxx similarity index 93% rename from panda/src/pipeline/semaphore.cxx rename to panda/src/pipeline/psemaphore.cxx index 6e8c7fb830..a9c2cb12bd 100644 --- a/panda/src/pipeline/semaphore.cxx +++ b/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 diff --git a/panda/src/pipeline/semaphore.h b/panda/src/pipeline/psemaphore.h similarity index 94% rename from panda/src/pipeline/semaphore.h rename to panda/src/pipeline/psemaphore.h index 6bb8672755..8fe89a0d82 100644 --- a/panda/src/pipeline/semaphore.h +++ b/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 diff --git a/panda/src/tinydisplay/tinyOsxGraphicsPipe.cxx b/panda/src/tinydisplay/tinyOsxGraphicsPipe.cxx index 8212da6518..7c3076e2c1 100644 --- a/panda/src/tinydisplay/tinyOsxGraphicsPipe.cxx +++ b/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); }