mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-03 02:15:43 -04:00
embed plugin windows within OSX browsers properly
This commit is contained in:
parent
37e76f402d
commit
9fa212a48a
@ -6,6 +6,8 @@
|
|||||||
#define USE_PACKAGES tinyxml openssl zlib jpeg x11
|
#define USE_PACKAGES tinyxml openssl zlib jpeg x11
|
||||||
#define TARGET p3d_plugin
|
#define TARGET p3d_plugin
|
||||||
#define LIB_PREFIX
|
#define LIB_PREFIX
|
||||||
|
|
||||||
|
#define OTHER_LIBS subprocbuffer
|
||||||
|
|
||||||
// We need this because we don't
|
// We need this because we don't
|
||||||
// include dtool_config.h.
|
// include dtool_config.h.
|
||||||
|
@ -39,7 +39,7 @@ inline HandleStream::
|
|||||||
// output.
|
// output.
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
inline void HandleStream::
|
inline void HandleStream::
|
||||||
open_read(Handle handle) {
|
open_read(FHandle handle) {
|
||||||
clear((ios::iostate)0);
|
clear((ios::iostate)0);
|
||||||
_buf.open_read(handle);
|
_buf.open_read(handle);
|
||||||
if (!_buf.is_open_read()) {
|
if (!_buf.is_open_read()) {
|
||||||
@ -55,7 +55,7 @@ open_read(Handle handle) {
|
|||||||
// output.
|
// output.
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
inline void HandleStream::
|
inline void HandleStream::
|
||||||
open_write(Handle handle) {
|
open_write(FHandle handle) {
|
||||||
clear((ios::iostate)0);
|
clear((ios::iostate)0);
|
||||||
_buf.open_write(handle);
|
_buf.open_write(handle);
|
||||||
if (!_buf.is_open_write()) {
|
if (!_buf.is_open_write()) {
|
||||||
|
@ -29,8 +29,8 @@ public:
|
|||||||
inline HandleStream();
|
inline HandleStream();
|
||||||
inline ~HandleStream();
|
inline ~HandleStream();
|
||||||
|
|
||||||
inline void open_read(Handle handle);
|
inline void open_read(FHandle handle);
|
||||||
inline void open_write(Handle handle);
|
inline void open_write(FHandle handle);
|
||||||
inline void close();
|
inline void close();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -69,7 +69,7 @@ HandleStreamBuf::
|
|||||||
// output.
|
// output.
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
void HandleStreamBuf::
|
void HandleStreamBuf::
|
||||||
open_read(Handle handle) {
|
open_read(FHandle handle) {
|
||||||
close();
|
close();
|
||||||
|
|
||||||
_handle = handle;
|
_handle = handle;
|
||||||
@ -84,7 +84,7 @@ open_read(Handle handle) {
|
|||||||
// output.
|
// output.
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
void HandleStreamBuf::
|
void HandleStreamBuf::
|
||||||
open_write(Handle handle) {
|
open_write(FHandle handle) {
|
||||||
close();
|
close();
|
||||||
|
|
||||||
_handle = handle;
|
_handle = handle;
|
||||||
|
@ -17,10 +17,10 @@
|
|||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
typedef HANDLE Handle;
|
typedef HANDLE FHandle;
|
||||||
#else
|
#else
|
||||||
// On POSIX, we use a file descriptor as a "handle".
|
// On POSIX, we use a file descriptor as a "handle".
|
||||||
typedef int Handle;
|
typedef int FHandle;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
@ -37,8 +37,8 @@ public:
|
|||||||
HandleStreamBuf();
|
HandleStreamBuf();
|
||||||
virtual ~HandleStreamBuf();
|
virtual ~HandleStreamBuf();
|
||||||
|
|
||||||
void open_read(Handle handle);
|
void open_read(FHandle handle);
|
||||||
void open_write(Handle handle);
|
void open_write(FHandle handle);
|
||||||
bool is_open_read() const;
|
bool is_open_read() const;
|
||||||
bool is_open_write() const;
|
bool is_open_write() const;
|
||||||
void close();
|
void close();
|
||||||
@ -56,7 +56,7 @@ private:
|
|||||||
bool _is_open_read;
|
bool _is_open_read;
|
||||||
bool _is_open_write;
|
bool _is_open_write;
|
||||||
|
|
||||||
Handle _handle;
|
FHandle _handle;
|
||||||
|
|
||||||
char *_buffer;
|
char *_buffer;
|
||||||
};
|
};
|
||||||
|
@ -69,6 +69,7 @@ P3D_instance_get_request_func *P3D_instance_get_request;
|
|||||||
P3D_check_request_func *P3D_check_request;
|
P3D_check_request_func *P3D_check_request;
|
||||||
P3D_request_finish_func *P3D_request_finish;
|
P3D_request_finish_func *P3D_request_finish;
|
||||||
P3D_instance_feed_url_stream_func *P3D_instance_feed_url_stream;
|
P3D_instance_feed_url_stream_func *P3D_instance_feed_url_stream;
|
||||||
|
P3D_instance_handle_event_func *P3D_instance_handle_event;
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
static HMODULE module = NULL;
|
static HMODULE module = NULL;
|
||||||
@ -206,6 +207,7 @@ load_plugin(const string &p3d_plugin_filename) {
|
|||||||
P3D_check_request = (P3D_check_request_func *)get_func(module, "P3D_check_request");
|
P3D_check_request = (P3D_check_request_func *)get_func(module, "P3D_check_request");
|
||||||
P3D_request_finish = (P3D_request_finish_func *)get_func(module, "P3D_request_finish");
|
P3D_request_finish = (P3D_request_finish_func *)get_func(module, "P3D_request_finish");
|
||||||
P3D_instance_feed_url_stream = (P3D_instance_feed_url_stream_func *)get_func(module, "P3D_instance_feed_url_stream");
|
P3D_instance_feed_url_stream = (P3D_instance_feed_url_stream_func *)get_func(module, "P3D_instance_feed_url_stream");
|
||||||
|
P3D_instance_handle_event = (P3D_instance_handle_event_func *)get_func(module, "P3D_instance_handle_event");
|
||||||
|
|
||||||
#undef get_func
|
#undef get_func
|
||||||
|
|
||||||
@ -244,7 +246,8 @@ load_plugin(const string &p3d_plugin_filename) {
|
|||||||
P3D_instance_get_request == NULL ||
|
P3D_instance_get_request == NULL ||
|
||||||
P3D_check_request == NULL ||
|
P3D_check_request == NULL ||
|
||||||
P3D_request_finish == NULL ||
|
P3D_request_finish == NULL ||
|
||||||
P3D_instance_feed_url_stream == NULL) {
|
P3D_instance_feed_url_stream == NULL ||
|
||||||
|
P3D_instance_handle_event == NULL) {
|
||||||
|
|
||||||
cerr
|
cerr
|
||||||
<< "Some function pointers not found:"
|
<< "Some function pointers not found:"
|
||||||
@ -283,6 +286,7 @@ load_plugin(const string &p3d_plugin_filename) {
|
|||||||
<< "\nP3D_check_request = " << P3D_check_request
|
<< "\nP3D_check_request = " << P3D_check_request
|
||||||
<< "\nP3D_request_finish = " << P3D_request_finish
|
<< "\nP3D_request_finish = " << P3D_request_finish
|
||||||
<< "\nP3D_instance_feed_url_stream = " << P3D_instance_feed_url_stream
|
<< "\nP3D_instance_feed_url_stream = " << P3D_instance_feed_url_stream
|
||||||
|
<< "\nP3D_instance_handle_event = " << P3D_instance_handle_event
|
||||||
<< "\n";
|
<< "\n";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -376,6 +380,7 @@ unload_dso() {
|
|||||||
P3D_check_request = NULL;
|
P3D_check_request = NULL;
|
||||||
P3D_request_finish = NULL;
|
P3D_request_finish = NULL;
|
||||||
P3D_instance_feed_url_stream = NULL;
|
P3D_instance_feed_url_stream = NULL;
|
||||||
|
P3D_instance_handle_event = NULL;
|
||||||
|
|
||||||
plugin_loaded = false;
|
plugin_loaded = false;
|
||||||
}
|
}
|
||||||
|
@ -55,6 +55,7 @@ extern P3D_instance_get_request_func *P3D_instance_get_request;
|
|||||||
extern P3D_check_request_func *P3D_check_request;
|
extern P3D_check_request_func *P3D_check_request;
|
||||||
extern P3D_request_finish_func *P3D_request_finish;
|
extern P3D_request_finish_func *P3D_request_finish;
|
||||||
extern P3D_instance_feed_url_stream_func *P3D_instance_feed_url_stream;
|
extern P3D_instance_feed_url_stream_func *P3D_instance_feed_url_stream;
|
||||||
|
extern P3D_instance_handle_event_func *P3D_instance_handle_event;
|
||||||
|
|
||||||
string get_plugin_basename();
|
string get_plugin_basename();
|
||||||
bool load_plugin(const string &p3d_plugin_filename);
|
bool load_plugin(const string &p3d_plugin_filename);
|
||||||
|
@ -27,15 +27,17 @@
|
|||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#endif // __APPLE__
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
typedef P3DWinSplashWindow SplashWindowType;
|
typedef P3DWinSplashWindow SplashWindowType;
|
||||||
#else
|
#elif defined(HAVE_X11)
|
||||||
#ifdef HAVE_X11
|
|
||||||
typedef P3DX11SplashWindow SplashWindowType;
|
typedef P3DX11SplashWindow SplashWindowType;
|
||||||
#else
|
#else
|
||||||
typedef P3DSplashWindow SplashWindowType;
|
typedef P3DSplashWindow SplashWindowType;
|
||||||
#endif
|
#endif
|
||||||
#endif
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: P3DInstance::Constructor
|
// Function: P3DInstance::Constructor
|
||||||
@ -63,6 +65,13 @@ P3DInstance(P3D_request_ready_func *func, void *user_data) :
|
|||||||
_instance_window_opened = false;
|
_instance_window_opened = false;
|
||||||
_requested_stop = false;
|
_requested_stop = false;
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
_shared_fd = -1;
|
||||||
|
_shared_mmap_size = 0;
|
||||||
|
_swbuffer = NULL;
|
||||||
|
_reversed_buffer = NULL;
|
||||||
|
#endif // __APPLE__
|
||||||
|
|
||||||
// Set some initial properties.
|
// Set some initial properties.
|
||||||
_panda_script_object->set_float_property("downloadProgress", 0.0);
|
_panda_script_object->set_float_property("downloadProgress", 0.0);
|
||||||
}
|
}
|
||||||
@ -95,6 +104,19 @@ P3DInstance::
|
|||||||
_splash_window = NULL;
|
_splash_window = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
if (_swbuffer != NULL) {
|
||||||
|
SubprocessWindowBuffer::destroy_buffer(_shared_fd, _shared_mmap_size,
|
||||||
|
_shared_filename, _swbuffer);
|
||||||
|
_swbuffer = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_reversed_buffer != NULL) {
|
||||||
|
delete[] _reversed_buffer;
|
||||||
|
_reversed_buffer = NULL;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
DESTROY_LOCK(_request_lock);
|
DESTROY_LOCK(_request_lock);
|
||||||
|
|
||||||
// TODO: empty _raw_requests and _baked_requests queues, and
|
// TODO: empty _raw_requests and _baked_requests queues, and
|
||||||
@ -184,6 +206,24 @@ set_wparams(const P3DWindowParams &wparams) {
|
|||||||
xcommand->SetAttribute("cmd", "setup_window");
|
xcommand->SetAttribute("cmd", "setup_window");
|
||||||
xcommand->SetAttribute("instance_id", get_instance_id());
|
xcommand->SetAttribute("instance_id", get_instance_id());
|
||||||
TiXmlElement *xwparams = _wparams.make_xml();
|
TiXmlElement *xwparams = _wparams.make_xml();
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
// On Mac, we have to communicate the results of the rendering
|
||||||
|
// back via shared memory, instead of directly parenting windows
|
||||||
|
// to the browser. Set up this mechanism.
|
||||||
|
int x_size = _wparams.get_win_width();
|
||||||
|
int y_size = _wparams.get_win_height();
|
||||||
|
nout << "size = " << x_size << " * " << y_size << "\n" << flush;
|
||||||
|
if (_shared_fd == -1 && x_size != 0 && y_size != 0) {
|
||||||
|
_swbuffer = SubprocessWindowBuffer::new_buffer
|
||||||
|
(_shared_fd, _shared_mmap_size, _shared_filename, x_size, y_size);
|
||||||
|
if (_swbuffer != NULL) {
|
||||||
|
_reversed_buffer = new char[_swbuffer->get_framebuffer_size()];
|
||||||
|
}
|
||||||
|
|
||||||
|
xwparams->SetAttribute("subprocess_window", _shared_filename);
|
||||||
|
}
|
||||||
|
#endif // __APPLE__
|
||||||
|
|
||||||
doc->LinkEndChild(decl);
|
doc->LinkEndChild(decl);
|
||||||
doc->LinkEndChild(xcommand);
|
doc->LinkEndChild(xcommand);
|
||||||
@ -425,6 +465,85 @@ feed_url_stream(int unique_id,
|
|||||||
return download_ok;
|
return download_ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: P3DInstance::handle_event
|
||||||
|
// Access: Public
|
||||||
|
// Description: Responds to the os-generated window event.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
void P3DInstance::
|
||||||
|
handle_event(P3D_event_data event) {
|
||||||
|
#ifdef _WIN32
|
||||||
|
// This function is not used in Win32 and does nothing.
|
||||||
|
|
||||||
|
#elif defined(__APPLE__)
|
||||||
|
EventRecord *er = event._event;
|
||||||
|
|
||||||
|
switch (er->what) {
|
||||||
|
case nullEvent:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case mouseDown:
|
||||||
|
case mouseUp:
|
||||||
|
{
|
||||||
|
Point pt = er->where;
|
||||||
|
GlobalToLocal(&pt);
|
||||||
|
P3D_window_handle window = _wparams.get_parent_window();
|
||||||
|
cerr << "mouse " << pt.h << " " << pt.v << "\n";
|
||||||
|
if (_swbuffer != NULL) {
|
||||||
|
SubprocessWindowBuffer::Event swb_event;
|
||||||
|
swb_event._up = (er->what == mouseUp);
|
||||||
|
swb_event._x = pt.h;
|
||||||
|
swb_event._y = pt.v;
|
||||||
|
_swbuffer->add_event(swb_event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case keyDown:
|
||||||
|
case keyUp:
|
||||||
|
case autoKey:
|
||||||
|
cerr << "keycode: " << (er->message & 0xffff) << "\n";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case updateEvt:
|
||||||
|
paint_window();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case activateEvt:
|
||||||
|
cerr << "activate window: " << er->message << "\n";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case diskEvt:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case osEvt:
|
||||||
|
if ((er->message & 0xf0000000) == suspendResumeMessage) {
|
||||||
|
if (er->message & 1) {
|
||||||
|
cerr << "suspend\n";
|
||||||
|
} else {
|
||||||
|
cerr << "resume\n";
|
||||||
|
}
|
||||||
|
} else if ((er->message & 0xf0000000) == mouseMovedMessage) {
|
||||||
|
cerr << "mouse moved\n";
|
||||||
|
} else {
|
||||||
|
cerr << "unhandled osEvt: " << hex << er->message << dec << "\n";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case kHighLevelEvent:
|
||||||
|
cerr << "high level: " << er->message << "\n";
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
cerr << "unhandled event: " << er->what << ", " << er->message << "\n";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif defined(HAVE_X11)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: P3DInstance::add_package
|
// Function: P3DInstance::add_package
|
||||||
// Access: Public
|
// Access: Public
|
||||||
@ -811,6 +930,81 @@ install_progress(P3DPackage *package, double progress) {
|
|||||||
_panda_script_object->set_float_property("downloadProgress", progress);
|
_panda_script_object->set_float_property("downloadProgress", progress);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: P3DInstance::paint_window
|
||||||
|
// Access: Private
|
||||||
|
// Description: Actually paints the rendered image to the browser
|
||||||
|
// window. This is only implemented (and needed) for
|
||||||
|
// OSX, where the child process isn't allowed to do it
|
||||||
|
// directly.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
void P3DInstance::
|
||||||
|
paint_window() {
|
||||||
|
#ifdef __APPLE__
|
||||||
|
if (_swbuffer == NULL) {
|
||||||
|
nout << "no _swbuffer\n";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QDErr err;
|
||||||
|
|
||||||
|
// blit rendered framebuffer into window backing store
|
||||||
|
int x_size = min(_wparams.get_win_width(), _swbuffer->get_x_size());
|
||||||
|
int y_size = min(_wparams.get_win_height(), _swbuffer->get_y_size());
|
||||||
|
Rect src_rect = {0, 0, y_size, x_size};
|
||||||
|
Rect ddrc_rect = {0, 0, y_size, x_size};
|
||||||
|
|
||||||
|
size_t rowsize = _swbuffer->get_row_size();
|
||||||
|
|
||||||
|
if (_swbuffer->ready_for_read()) {
|
||||||
|
// Copy the new framebuffer image from the child process.
|
||||||
|
const void *framebuffer = _swbuffer->open_read_framebuffer();
|
||||||
|
|
||||||
|
// We have to reverse the image vertically first (different
|
||||||
|
// conventions between Panda and Mac).
|
||||||
|
for (int yi = 0; yi < y_size; ++yi) {
|
||||||
|
memcpy(_reversed_buffer + (y_size - 1 - yi) * rowsize,
|
||||||
|
(char *)framebuffer + yi * rowsize,
|
||||||
|
rowsize);
|
||||||
|
}
|
||||||
|
|
||||||
|
_swbuffer->close_read_framebuffer();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// No frame ready. Just re-paint the frame we had saved last
|
||||||
|
// time.
|
||||||
|
}
|
||||||
|
|
||||||
|
// create a GWorld containing our image
|
||||||
|
GWorldPtr pGWorld;
|
||||||
|
err = NewGWorldFromPtr(&pGWorld, k32BGRAPixelFormat, &src_rect, 0, 0, 0,
|
||||||
|
_reversed_buffer, rowsize);
|
||||||
|
if (err != noErr) {
|
||||||
|
nout << " error in NewGWorldFromPtr, called from paint_window()\n";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
GrafPtr out_port = _wparams.get_parent_window()._port;
|
||||||
|
GrafPtr portSave = NULL;
|
||||||
|
Boolean portChanged = QDSwapPort(out_port, &portSave);
|
||||||
|
|
||||||
|
// Make sure the clipping rectangle isn't in the way. Is there a
|
||||||
|
// better way to eliminate the cliprect from consideration?
|
||||||
|
Rect r = { 0, 0, 0x7fff, 0x7fff };
|
||||||
|
ClipRect(&r);
|
||||||
|
|
||||||
|
CopyBits(GetPortBitMapForCopyBits(pGWorld),
|
||||||
|
GetPortBitMapForCopyBits(out_port),
|
||||||
|
&src_rect, &ddrc_rect, srcCopy, 0);
|
||||||
|
|
||||||
|
if (portChanged) {
|
||||||
|
QDSwapPort(portSave, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
DisposeGWorld(pGWorld);
|
||||||
|
#endif // __APPLE__
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: P3DInstance::SplashDownload::Constructor
|
// Function: P3DInstance::SplashDownload::Constructor
|
||||||
// Access: Public
|
// Access: Public
|
||||||
|
@ -22,6 +22,10 @@
|
|||||||
#include "p3dReferenceCount.h"
|
#include "p3dReferenceCount.h"
|
||||||
#include "get_tinyxml.h"
|
#include "get_tinyxml.h"
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
#include "subprocessWindowBuffer.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <deque>
|
#include <deque>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
@ -65,6 +69,8 @@ public:
|
|||||||
const unsigned char *this_data,
|
const unsigned char *this_data,
|
||||||
size_t this_data_size);
|
size_t this_data_size);
|
||||||
|
|
||||||
|
void handle_event(P3D_event_data event);
|
||||||
|
|
||||||
inline int get_instance_id() const;
|
inline int get_instance_id() const;
|
||||||
inline const string &get_session_key() const;
|
inline const string &get_session_key() const;
|
||||||
inline const string &get_python_version() const;
|
inline const string &get_python_version() const;
|
||||||
@ -101,6 +107,8 @@ private:
|
|||||||
void make_splash_window();
|
void make_splash_window();
|
||||||
void install_progress(P3DPackage *package, double progress);
|
void install_progress(P3DPackage *package, double progress);
|
||||||
|
|
||||||
|
void paint_window();
|
||||||
|
|
||||||
P3D_request_ready_func *_func;
|
P3D_request_ready_func *_func;
|
||||||
P3D_object *_browser_script_object;
|
P3D_object *_browser_script_object;
|
||||||
P3DToplevelObject *_panda_script_object;
|
P3DToplevelObject *_panda_script_object;
|
||||||
@ -118,6 +126,17 @@ private:
|
|||||||
// Not ref-counted: session is the parent.
|
// Not ref-counted: session is the parent.
|
||||||
P3DSession *_session;
|
P3DSession *_session;
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
// On OSX, we have to get a copy of the framebuffer data back from
|
||||||
|
// the child process, and draw it to the window, here in the parent
|
||||||
|
// process. Crazy!
|
||||||
|
int _shared_fd;
|
||||||
|
size_t _shared_mmap_size;
|
||||||
|
string _shared_filename;
|
||||||
|
SubprocessWindowBuffer *_swbuffer;
|
||||||
|
char *_reversed_buffer;
|
||||||
|
#endif __APPLE__
|
||||||
|
|
||||||
P3DSplashWindow *_splash_window;
|
P3DSplashWindow *_splash_window;
|
||||||
bool _instance_window_opened;
|
bool _instance_window_opened;
|
||||||
|
|
||||||
|
@ -889,27 +889,37 @@ setup_window(P3DCInstance *inst, TiXmlElement *xwparams) {
|
|||||||
xwparams->Attribute("win_height", &win_height);
|
xwparams->Attribute("win_height", &win_height);
|
||||||
|
|
||||||
long parent_window_handle = 0;
|
long parent_window_handle = 0;
|
||||||
|
const char *subprocess_window = "";
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
int hwnd;
|
int hwnd;
|
||||||
if (xwparams->Attribute("parent_hwnd", &hwnd)) {
|
if (xwparams->Attribute("parent_hwnd", &hwnd)) {
|
||||||
parent_window_handle = (long)hwnd;
|
parent_window_handle = (long)hwnd;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
#ifdef HAVE_X11
|
#elif __APPLE__
|
||||||
|
// On Mac, we don't parent windows directly to the browser; instead,
|
||||||
|
// we have to go through this subprocess-window nonsense.
|
||||||
|
|
||||||
|
subprocess_window = xwparams->Attribute("subprocess_window");
|
||||||
|
if (subprocess_window == NULL) {
|
||||||
|
subprocess_window = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif defined(HAVE_X11)
|
||||||
// Bad! Casting to int loses precision.
|
// Bad! Casting to int loses precision.
|
||||||
int xwindow;
|
int xwindow;
|
||||||
if (xwparams->Attribute("parent_xwindow", &xwindow)) {
|
if (xwparams->Attribute("parent_xwindow", &xwindow)) {
|
||||||
parent_window_handle = (unsigned long)xwindow;
|
parent_window_handle = (long)xwindow;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// TODO: direct this into the particular instance. This will
|
// TODO: direct this into the particular instance. This will
|
||||||
// require a specialized ShowBase replacement.
|
// require a specialized ShowBase replacement.
|
||||||
PyObject *result = PyObject_CallMethod
|
PyObject *result = PyObject_CallMethod
|
||||||
(_runner, (char *)"setupWindow", (char *)"siiiii", window_type.c_str(),
|
(_runner, (char *)"setupWindow", (char *)"siiiiis", window_type.c_str(),
|
||||||
win_x, win_y, win_width, win_height,
|
win_x, win_y, win_width, win_height,
|
||||||
parent_window_handle);
|
parent_window_handle, subprocess_window);
|
||||||
if (result == NULL) {
|
if (result == NULL) {
|
||||||
PyErr_Print();
|
PyErr_Print();
|
||||||
}
|
}
|
||||||
|
@ -79,8 +79,11 @@ make_xml() {
|
|||||||
xwparams->SetAttribute("win_height", _win_height);
|
xwparams->SetAttribute("win_height", _win_height);
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
xwparams->SetAttribute("parent_hwnd", (int)_parent_window._hwnd);
|
xwparams->SetAttribute("parent_hwnd", (int)_parent_window._hwnd);
|
||||||
#endif
|
|
||||||
#ifdef HAVE_X11
|
#elif defined(__APPLE__)
|
||||||
|
// The subprocess_window setting is applied by the caller.
|
||||||
|
|
||||||
|
#elif defined(HAVE_X11)
|
||||||
xwparams->SetAttribute("parent_xwindow", (unsigned long)_parent_window._xwindow);
|
xwparams->SetAttribute("parent_xwindow", (unsigned long)_parent_window._xwindow);
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
|
@ -406,3 +406,11 @@ P3D_instance_feed_url_stream(P3D_instance *instance, int unique_id,
|
|||||||
RELEASE_LOCK(_api_lock);
|
RELEASE_LOCK(_api_lock);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
P3D_instance_handle_event(P3D_instance *instance, P3D_event_data event) {
|
||||||
|
assert(P3DInstanceManager::get_global_ptr()->is_initialized());
|
||||||
|
ACQUIRE_LOCK(_api_lock);
|
||||||
|
((P3DInstance *)instance)->handle_event(event);
|
||||||
|
RELEASE_LOCK(_api_lock);
|
||||||
|
}
|
||||||
|
@ -57,6 +57,10 @@
|
|||||||
|
|
||||||
#endif /* _WIN32 */
|
#endif /* _WIN32 */
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
#include <Carbon/Carbon.h>
|
||||||
|
#endif /* __APPLE__ */
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
@ -130,14 +134,14 @@ typedef struct {
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
HWND _hwnd;
|
HWND _hwnd;
|
||||||
#endif
|
|
||||||
#ifdef HAVE_X11
|
#elif defined(__APPLE__)
|
||||||
|
GrafPtr _port;
|
||||||
|
|
||||||
|
#elif defined(HAVE_X11)
|
||||||
unsigned long _xwindow;
|
unsigned long _xwindow;
|
||||||
void *_xdisplay;
|
void *_xdisplay;
|
||||||
#endif
|
#endif
|
||||||
#ifdef __APPLE__
|
|
||||||
void *_nswindow;
|
|
||||||
#endif
|
|
||||||
} P3D_window_handle;
|
} P3D_window_handle;
|
||||||
|
|
||||||
/* This enum lists the different kinds of window types that may be
|
/* This enum lists the different kinds of window types that may be
|
||||||
@ -781,6 +785,29 @@ P3D_instance_feed_url_stream_func(P3D_instance *instance, int unique_id,
|
|||||||
const void *this_data,
|
const void *this_data,
|
||||||
size_t this_data_size);
|
size_t this_data_size);
|
||||||
|
|
||||||
|
/* This structure abstracts out the event pointer data types for the
|
||||||
|
different platforms, as passed to P3D_instance_handle_event(),
|
||||||
|
below. */
|
||||||
|
typedef struct {
|
||||||
|
#ifdef _WIN32
|
||||||
|
// Not used for Win32.
|
||||||
|
|
||||||
|
#elif defined(__APPLE__)
|
||||||
|
EventRecord *_event;
|
||||||
|
|
||||||
|
#elif defined(HAVE_X11)
|
||||||
|
// XEvent *_event; ?
|
||||||
|
#endif
|
||||||
|
} P3D_event_data;
|
||||||
|
|
||||||
|
/* Use this function to supply a new os-specific window event to the
|
||||||
|
plugin. This is presently used only on OSX, where the window
|
||||||
|
events are needed for proper plugin handling; and possibly also on
|
||||||
|
X11. On Windows, window events are handled natively by the plugin.
|
||||||
|
*/
|
||||||
|
typedef void
|
||||||
|
P3D_instance_handle_event_func(P3D_instance *instance, P3D_event_data event);
|
||||||
|
|
||||||
#ifdef P3D_FUNCTION_PROTOTYPES
|
#ifdef P3D_FUNCTION_PROTOTYPES
|
||||||
|
|
||||||
/* Define all of the actual prototypes for the above functions. */
|
/* Define all of the actual prototypes for the above functions. */
|
||||||
@ -820,6 +847,7 @@ EXPCL_P3D_PLUGIN P3D_instance_get_request_func P3D_instance_get_request;
|
|||||||
EXPCL_P3D_PLUGIN P3D_check_request_func P3D_check_request;
|
EXPCL_P3D_PLUGIN P3D_check_request_func P3D_check_request;
|
||||||
EXPCL_P3D_PLUGIN P3D_request_finish_func P3D_request_finish;
|
EXPCL_P3D_PLUGIN P3D_request_finish_func P3D_request_finish;
|
||||||
EXPCL_P3D_PLUGIN P3D_instance_feed_url_stream_func P3D_instance_feed_url_stream;
|
EXPCL_P3D_PLUGIN P3D_instance_feed_url_stream_func P3D_instance_feed_url_stream;
|
||||||
|
EXPCL_P3D_PLUGIN P3D_instance_handle_event_func P3D_instance_handle_event;
|
||||||
|
|
||||||
#endif /* P3D_FUNCTION_PROTOTYPES */
|
#endif /* P3D_FUNCTION_PROTOTYPES */
|
||||||
|
|
||||||
|
@ -438,7 +438,7 @@ handle_request(P3D_request *request) {
|
|||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: PPInstance::handle_request_loop
|
// Function: PPInstance::handle_request_loop
|
||||||
// Access: Private, Static
|
// Access: Public, Static
|
||||||
// Description: Checks for any new requests from the plugin, and
|
// Description: Checks for any new requests from the plugin, and
|
||||||
// dispatches them to the appropriate PPInstance. This
|
// dispatches them to the appropriate PPInstance. This
|
||||||
// function is called only in the main thread.
|
// function is called only in the main thread.
|
||||||
@ -461,6 +461,47 @@ handle_request_loop() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: PPInstance::handle_event
|
||||||
|
// Access: Public
|
||||||
|
// Description: Called by the browser as new window events are
|
||||||
|
// generated.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
void PPInstance::
|
||||||
|
handle_event(void *event) {
|
||||||
|
// This is a good time to check for new requests.
|
||||||
|
handle_request_loop();
|
||||||
|
|
||||||
|
if (_p3d_inst == NULL) {
|
||||||
|
// Ignore events that come in before we've launched the instance.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
EventRecord *er = (EventRecord *)event;
|
||||||
|
|
||||||
|
switch (er->what) {
|
||||||
|
case nullEvent:
|
||||||
|
// We appear to get this event pretty frequently when nothing else
|
||||||
|
// is going on. Great; we'll take advantage of it to invalidate
|
||||||
|
// the instance rectangle, which will cause updateEvt to be
|
||||||
|
// triggered (if the instance is still onscreen).
|
||||||
|
|
||||||
|
if (_got_window) {
|
||||||
|
NPRect rect = { 0, 0, _window.height, _window.width };
|
||||||
|
browser->invalidaterect(_npp_instance, &rect);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// All other events we feed down to the plugin for processing.
|
||||||
|
P3D_event_data edata;
|
||||||
|
edata._event = er;
|
||||||
|
P3D_instance_handle_event(_p3d_inst, edata);
|
||||||
|
|
||||||
|
#endif // __APPLE__
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: PPInstance::get_panda_script_object
|
// Function: PPInstance::get_panda_script_object
|
||||||
// Access: Public
|
// Access: Public
|
||||||
@ -972,14 +1013,24 @@ send_window() {
|
|||||||
// right spot.
|
// right spot.
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
parent_window._hwnd = (HWND)(_window.window);
|
parent_window._hwnd = (HWND)(_window.window);
|
||||||
#endif
|
x = 0;
|
||||||
#ifdef HAVE_X11
|
y = 0;
|
||||||
|
|
||||||
|
#elif defined(__APPLE__)
|
||||||
|
logfile << "windowed plugin\n" << flush;
|
||||||
|
NP_Port *port = (NP_Port *)_window.window;
|
||||||
|
logfile << "portx, porty = " << port->portx << ", " << port->porty << "\n";
|
||||||
|
logfile << "x, y = " << _window.x << ", " << _window.y << "\n";
|
||||||
|
parent_window._port = port->port;
|
||||||
|
|
||||||
|
#elif defined(HAVE_X11)
|
||||||
// We make it an 'unsigned long' instead of 'Window'
|
// We make it an 'unsigned long' instead of 'Window'
|
||||||
// to avoid nppanda3d.so getting a dependency on X11.
|
// to avoid nppanda3d.so getting a dependency on X11.
|
||||||
parent_window._xwindow = (unsigned long)(_window.window);
|
parent_window._xwindow = (unsigned long)(_window.window);
|
||||||
#endif
|
|
||||||
x = 0;
|
x = 0;
|
||||||
y = 0;
|
y = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// We have a "windowless" plugin. Parent our window directly to
|
// We have a "windowless" plugin. Parent our window directly to
|
||||||
// the browser window.
|
// the browser window.
|
||||||
@ -990,8 +1041,15 @@ send_window() {
|
|||||||
&hwnd) == NPERR_NO_ERROR) {
|
&hwnd) == NPERR_NO_ERROR) {
|
||||||
parent_window._hwnd = hwnd;
|
parent_window._hwnd = hwnd;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
#ifdef HAVE_X11
|
#elif defined(__APPLE__)
|
||||||
|
logfile << "windowless plugin\n" << flush;
|
||||||
|
NP_Port *port = (NP_Port *)_window.window;
|
||||||
|
logfile << "portx, porty = " << port->portx << ", " << port->porty << "\n";
|
||||||
|
logfile << "x, y = " << _window.x << ", " << _window.y << "\n";
|
||||||
|
parent_window._port = port->port;
|
||||||
|
|
||||||
|
#elif defined(HAVE_X11)
|
||||||
parent_window._xwindow = 0;
|
parent_window._xwindow = 0;
|
||||||
unsigned long win;
|
unsigned long win;
|
||||||
if (browser->getvalue(_npp_instance, NPNVnetscapeWindow,
|
if (browser->getvalue(_npp_instance, NPNVnetscapeWindow,
|
||||||
|
@ -53,6 +53,8 @@ public:
|
|||||||
void handle_request(P3D_request *request);
|
void handle_request(P3D_request *request);
|
||||||
static void handle_request_loop();
|
static void handle_request_loop();
|
||||||
|
|
||||||
|
void handle_event(void *event);
|
||||||
|
|
||||||
NPObject *get_panda_script_object();
|
NPObject *get_panda_script_object();
|
||||||
|
|
||||||
void p3dobj_to_variant(NPVariant *result, P3D_object *object);
|
void p3dobj_to_variant(NPVariant *result, P3D_object *object);
|
||||||
|
@ -331,8 +331,10 @@ int16
|
|||||||
NPP_HandleEvent(NPP instance, void *event) {
|
NPP_HandleEvent(NPP instance, void *event) {
|
||||||
// logfile << "HandleEvent\n" << flush;
|
// logfile << "HandleEvent\n" << flush;
|
||||||
|
|
||||||
// Here's a fine opportunity to check for new requests.
|
PPInstance *inst = (PPInstance *)(instance->pdata);
|
||||||
PPInstance::handle_request_loop();
|
assert(inst != NULL);
|
||||||
|
|
||||||
|
inst->handle_event(event);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -258,8 +258,36 @@ class AppRunner(DirectObject):
|
|||||||
|
|
||||||
self.startIfReady()
|
self.startIfReady()
|
||||||
|
|
||||||
def setupWindow(self, windowType, x, y, width, height, parent):
|
def clearWindowPrc(self):
|
||||||
print "setupWindow %s, %s, %s, %s, %s, %s" % (windowType, x, y, width, height, parent)
|
""" Clears the windowPrc file that was created in a previous
|
||||||
|
call to setupWindow(), if any. """
|
||||||
|
|
||||||
|
if self.windowPrc:
|
||||||
|
unloadPrcFile(self.windowPrc)
|
||||||
|
self.windowPrc = None
|
||||||
|
|
||||||
|
def setupWindow(self, windowType, x, y, width, height,
|
||||||
|
parent, subprocessWindow):
|
||||||
|
""" Applies the indicated window parameters to the prc
|
||||||
|
settings, for future windows; or applies them directly to the
|
||||||
|
main window if the window has already been opened. """
|
||||||
|
|
||||||
|
print "setupWindow %s, %s, %s, %s, %s, %s, %s" % (windowType, x, y, width, height, parent, subprocessWindow)
|
||||||
|
|
||||||
|
if self.started and base.win:
|
||||||
|
# If we've already got a window, this must be a
|
||||||
|
# resize/reposition request.
|
||||||
|
wp = WindowProperties()
|
||||||
|
if x or y or windowType == 'embedded':
|
||||||
|
wp.setOrigin(x, y)
|
||||||
|
if width or height:
|
||||||
|
wp.setSize(width, height)
|
||||||
|
base.win.requestProperties(wp)
|
||||||
|
return
|
||||||
|
|
||||||
|
# If we haven't got a window already, start 'er up. Apply the
|
||||||
|
# requested setting to the prc file.
|
||||||
|
|
||||||
if windowType == 'hidden':
|
if windowType == 'hidden':
|
||||||
data = 'window-type none\n'
|
data = 'window-type none\n'
|
||||||
else:
|
else:
|
||||||
@ -271,33 +299,21 @@ class AppRunner(DirectObject):
|
|||||||
data += 'fullscreen 0\n'
|
data += 'fullscreen 0\n'
|
||||||
|
|
||||||
if windowType == 'embedded':
|
if windowType == 'embedded':
|
||||||
data += 'parent-window-handle %s\n' % (parent)
|
data += 'parent-window-handle %s\nsubprocess-window %s\n' % (
|
||||||
|
parent, subprocessWindow)
|
||||||
else:
|
else:
|
||||||
data += 'parent-window-handle 0\n'
|
data += 'parent-window-handle 0\nsubprocess-window \n'
|
||||||
|
|
||||||
if x or y or windowType == 'embedded':
|
if x or y or windowType == 'embedded':
|
||||||
data += 'win-origin %s %s\n' % (x, y)
|
data += 'win-origin %s %s\n' % (x, y)
|
||||||
if width or height:
|
if width or height:
|
||||||
data += 'win-size %s %s\n' % (width, height)
|
data += 'win-size %s %s\n' % (width, height)
|
||||||
|
|
||||||
if self.windowPrc:
|
self.clearWindowPrc()
|
||||||
unloadPrcFile(self.windowPrc)
|
|
||||||
self.windowPrc = loadPrcFileData("setupWindow", data)
|
self.windowPrc = loadPrcFileData("setupWindow", data)
|
||||||
|
|
||||||
if self.started and base.win:
|
self.gotWindow = True
|
||||||
# If we've already got a window, this must be a
|
self.startIfReady()
|
||||||
# resize/reposition request.
|
|
||||||
wp = WindowProperties()
|
|
||||||
if x or y or windowType == 'embedded':
|
|
||||||
wp.setOrigin(x, y)
|
|
||||||
if width or height:
|
|
||||||
wp.setSize(width, height)
|
|
||||||
base.win.requestProperties(wp)
|
|
||||||
|
|
||||||
else:
|
|
||||||
# If we haven't got a window already, start 'er up.
|
|
||||||
self.gotWindow = True
|
|
||||||
self.startIfReady()
|
|
||||||
|
|
||||||
def setRequestFunc(self, func):
|
def setRequestFunc(self, func):
|
||||||
""" This method is called by the plugin at startup to supply a
|
""" This method is called by the plugin at startup to supply a
|
||||||
@ -319,9 +335,15 @@ class AppRunner(DirectObject):
|
|||||||
successfully opened. """
|
successfully opened. """
|
||||||
|
|
||||||
if not self.windowOpened:
|
if not self.windowOpened:
|
||||||
self.notifyRequest('onwindowopen')
|
|
||||||
self.windowOpened = True
|
self.windowOpened = True
|
||||||
|
|
||||||
|
# Now that the window is open, we don't need to keep those
|
||||||
|
# prc settings around any more.
|
||||||
|
self.clearWindowPrc()
|
||||||
|
|
||||||
|
# Inform the plugin and browser.
|
||||||
|
self.notifyRequest('onwindowopen')
|
||||||
|
|
||||||
def notifyRequest(self, message):
|
def notifyRequest(self, message):
|
||||||
""" Delivers a notify request to the browser. This is a "this
|
""" Delivers a notify request to the browser. This is a "this
|
||||||
happened" type notification; it optionally triggers some
|
happened" type notification; it optionally triggers some
|
||||||
@ -340,10 +362,10 @@ class AppRunner(DirectObject):
|
|||||||
|
|
||||||
def evalScript(self, expression, needsResponse = False):
|
def evalScript(self, expression, needsResponse = False):
|
||||||
""" Evaluates an arbitrary JavaScript expression in the global
|
""" Evaluates an arbitrary JavaScript expression in the global
|
||||||
DOM space. This may be deferred if necessary if self.dom has
|
DOM space. This may be deferred if necessary if needsResponse
|
||||||
not yet been assigned. If needsResponse is true, this waits
|
is False and self.dom has not yet been assigned. If
|
||||||
for the value and returns it, which means it may not be
|
needsResponse is true, this waits for the value and returns
|
||||||
deferred. """
|
it, which means it cannot be deferred. """
|
||||||
|
|
||||||
if not self.dom:
|
if not self.dom:
|
||||||
# Defer the expression.
|
# Defer the expression.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user