diff --git a/direct/src/plugin/Sources.pp b/direct/src/plugin/Sources.pp index 92b907bdb4..b131af5d9b 100644 --- a/direct/src/plugin/Sources.pp +++ b/direct/src/plugin/Sources.pp @@ -43,6 +43,7 @@ p3dMultifileReader.h p3dMultifileReader.I \ p3dNoneObject.h \ p3dObject.h p3dObject.I \ + p3dOsxSplashWindow.h p3dOsxSplashWindow.I \ p3dPackage.h p3dPackage.I \ p3dPythonObject.h \ p3dReferenceCount.h p3dReferenceCount.I \ @@ -71,6 +72,7 @@ p3dMultifileReader.cxx \ p3dNoneObject.cxx \ p3dObject.cxx \ + p3dOsxSplashWindow.cxx \ p3dPackage.cxx \ p3dPythonObject.cxx \ p3dReferenceCount.cxx \ diff --git a/direct/src/plugin/p3dInstance.cxx b/direct/src/plugin/p3dInstance.cxx index addb650e7e..fe01b6ee0b 100644 --- a/direct/src/plugin/p3dInstance.cxx +++ b/direct/src/plugin/p3dInstance.cxx @@ -19,6 +19,7 @@ #include "p3dPackage.h" #include "p3dSplashWindow.h" #include "p3dWinSplashWindow.h" +#include "p3dOsxSplashWindow.h" #include "p3dX11SplashWindow.h" #include "p3dObject.h" #include "p3dToplevelObject.h" @@ -34,6 +35,8 @@ #ifdef _WIN32 typedef P3DWinSplashWindow SplashWindowType; +#elif defined(__APPLE__) +typedef P3DOsxSplashWindow SplashWindowType; #elif defined(HAVE_X11) typedef P3DX11SplashWindow SplashWindowType; #else @@ -153,8 +156,8 @@ set_fparams(const P3DFileParams &fparams) { // Generate a special notification: onpluginload, indicating the // plugin has read its parameters and is ready to be queried (even // if Python has not yet started). This notification is special - // because it is the only one generated at this level; the rest of - // them are generated by the Python code, once that is running. + // because it generated at the C++ level, here; most of them are + // generated by the Python code, once that is running. P3D_request *request = new P3D_request; request->_request_type = P3D_RT_notify; request->_request._notify._message = strdup("onpluginload"); @@ -475,6 +478,10 @@ feed_url_stream(int unique_id, //////////////////////////////////////////////////////////////////// void P3DInstance:: handle_event(P3D_event_data event) { + if (_splash_window != NULL) { + _splash_window->handle_event(event); + } + #ifdef _WIN32 // This function is not used in Win32 and does nothing. @@ -643,6 +650,20 @@ request_stop() { } } +//////////////////////////////////////////////////////////////////// +// Function: P3DInstance::request_refresh +// Access: Public +// Description: Asks the host to refresh the plugin window. This is +// only relevant for windowless plugins, for instance, +// the way OSX plugins always run. +//////////////////////////////////////////////////////////////////// +void P3DInstance:: +request_refresh() { + P3D_request *request = new P3D_request; + request->_request_type = P3D_RT_refresh; + add_baked_request(request); +} + //////////////////////////////////////////////////////////////////// // Function: P3DInstance::make_xml // Access: Public @@ -971,8 +992,7 @@ install_progress(P3DPackage *package, double progress) { void P3DInstance:: paint_window() { #ifdef __APPLE__ - if (_swbuffer == NULL) { - nout << "no _swbuffer\n"; + if (_swbuffer == NULL || !_instance_window_opened) { return; } diff --git a/direct/src/plugin/p3dInstance.h b/direct/src/plugin/p3dInstance.h index 5d218d9d20..49b89f9cba 100644 --- a/direct/src/plugin/p3dInstance.h +++ b/direct/src/plugin/p3dInstance.h @@ -82,6 +82,7 @@ public: void start_download(P3DDownload *download); inline bool is_started() const; void request_stop(); + void request_refresh(); TiXmlElement *make_xml(); diff --git a/direct/src/plugin/p3dOsxSplashWindow.I b/direct/src/plugin/p3dOsxSplashWindow.I new file mode 100644 index 0000000000..75d0726e87 --- /dev/null +++ b/direct/src/plugin/p3dOsxSplashWindow.I @@ -0,0 +1,14 @@ +// Filename: p3dOsxSplashWindow.I +// Created by: drose (16Jul09) +// +//////////////////////////////////////////////////////////////////// +// +// 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/direct/src/plugin/p3dOsxSplashWindow.cxx b/direct/src/plugin/p3dOsxSplashWindow.cxx new file mode 100644 index 0000000000..874cdfd5a2 --- /dev/null +++ b/direct/src/plugin/p3dOsxSplashWindow.cxx @@ -0,0 +1,264 @@ +// Filename: p3dOsxSplashWindow.cxx +// Created by: drose (16Jul09) +// +//////////////////////////////////////////////////////////////////// +// +// 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 "p3dOsxSplashWindow.h" + +#ifdef __APPLE__ + +#include + +//////////////////////////////////////////////////////////////////// +// Function: P3DOsxSplashWindow::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +P3DOsxSplashWindow:: +P3DOsxSplashWindow(P3DInstance *inst) : + P3DSplashWindow(inst) +{ + _image = NULL; + _image_data = NULL; + _install_progress = 0; +} + +//////////////////////////////////////////////////////////////////// +// Function: P3DOsxSplashWindow::Destructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +P3DOsxSplashWindow:: +~P3DOsxSplashWindow() { + if (_image != NULL) { + DisposeGWorld(_image); + } + + if (_image_data != NULL) { + delete[] _image_data; + _image_data = NULL; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: P3DOsxSplashWindow::set_image_filename +// Access: Public, Virtual +// Description: Specifies the name of a JPEG image file that is +// displayed in the center of the splash window. If +// image_filename_temp is true, the file is immediately +// deleted after it has been read. +//////////////////////////////////////////////////////////////////// +void P3DOsxSplashWindow:: +set_image_filename(const string &image_filename, + bool image_filename_temp) { + int num_channels, row_stride; + string data; + if (!read_image(image_filename, image_filename_temp, + _image_height, _image_width, num_channels, row_stride, + data)) { + return; + } + + QDErr err; + Rect src_rect = { 0, 0, _image_height, _image_width }; + + if (_image != NULL) { + DisposeGWorld(_image); + _image = NULL; + } + + if (_image_data != NULL) { + delete[] _image_data; + _image_data = NULL; + } + + // Now we need to copy from the RGB source image into the BGRA target image. + int new_row_stride = _image_width * 4; + _image_data = new char[new_row_stride * _image_height]; + for (int yi = 0; yi < _image_height; ++yi) { + char *dest = _image_data + yi * new_row_stride; + const char *source = data.data() + yi * row_stride; + for (int xi = 0; xi < _image_width; ++xi) { + char r = source[0]; + char g = source[1]; + char b = source[2]; +#ifndef __BIG_ENDIAN__ + // Little-endian. + dest[0] = b; + dest[1] = g; + dest[2] = r; + dest[3] = 0xff; +#else // __BIG_ENDIAN__ + // Big-endian. + dest[0] = 0xff; + dest[1] = r; + dest[2] = g; + dest[3] = b; +#endif // __BIG_ENDIAN__ + source += 3; + dest += 4; + } + } + + err = NewGWorldFromPtr(&_image, k32BGRAPixelFormat, &src_rect, 0, 0, 0, + _image_data, new_row_stride); + if (err != noErr) { + nout << " error in NewGWorldFromPtr, called from set_image_filename()\n"; + return; + } + + _inst->request_refresh(); +} + +//////////////////////////////////////////////////////////////////// +// Function: P3DOsxSplashWindow::set_install_label +// Access: Public, Virtual +// Description: Specifies the text that is displayed above the +// install progress bar. +//////////////////////////////////////////////////////////////////// +void P3DOsxSplashWindow:: +set_install_label(const string &install_label) { + _install_label = install_label; + _inst->request_refresh(); +} + +//////////////////////////////////////////////////////////////////// +// Function: P3DOsxSplashWindow::set_install_progress +// Access: Public, Virtual +// Description: Moves the install progress bar from 0.0 to 1.0. +//////////////////////////////////////////////////////////////////// +void P3DOsxSplashWindow:: +set_install_progress(double install_progress) { + if ((int)(install_progress * 500.0) != (int)(_install_progress * 500.0)) { + // Only request a refresh if we're changing substantially. + _inst->request_refresh(); + } + _install_progress = install_progress; +} + +//////////////////////////////////////////////////////////////////// +// Function: P3DOsxSplashWindow::handle_event +// Access: Public, Virtual +// Description: Deals with the event callback from the OS window +// system. +//////////////////////////////////////////////////////////////////// +void P3DOsxSplashWindow:: +handle_event(P3D_event_data event) { + EventRecord *er = event._event; + if (er->what == updateEvt) { + paint_window(); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: P3DOsxSplashWindow::paint_window +// Access: Private +// Description: Redraws the current splash window. +//////////////////////////////////////////////////////////////////// +void P3DOsxSplashWindow:: +paint_window() { + cerr << "paint_window, _image = " << _image << ", label = " << _install_label << "\n"; + GrafPtr out_port = _wparams.get_parent_window()._port; + GrafPtr portSave = NULL; + Boolean portChanged = QDSwapPort(out_port, &portSave); + + int win_width = _wparams.get_win_width(); + int win_height = _wparams.get_win_height(); + + Rect r = { 0, 0, win_height, win_width }; + ClipRect(&r); + + EraseRect(&r); + + if (_image != NULL) { + Rect src_rect = { 0, 0, _image_height, _image_width }; + Rect dest_rect; + + // Determine the relative size of image and window. + int win_cx = win_width / 2; + int win_cy = win_height / 2; + + if (_image_width <= win_width && _image_height <= win_height) { + // The bitmap fits within the window; center it. + + // This is the top-left corner of the bitmap in window coordinates. + int p_x = win_cx - _image_width / 2; + int p_y = win_cy - _image_height / 2; + + dest_rect.left = p_x; + dest_rect.top = p_y; + dest_rect.right = p_x + _image_width; + dest_rect.bottom = p_y + _image_height; + + } else { + // The bitmap is larger than the window; scale it down. + double x_scale = (double)win_width / (double)_image_width; + double y_scale = (double)win_height / (double)_image_height; + double scale = min(x_scale, y_scale); + int sc_width = (int)(_image_width * scale); + int sc_height = (int)(_image_height * scale); + + int p_x = win_cx - sc_width / 2; + int p_y = win_cy - sc_height / 2; + + dest_rect.left = p_x; + dest_rect.top = p_y; + dest_rect.right = p_x + sc_width; + dest_rect.bottom = p_y + sc_height; + } + + CopyBits(GetPortBitMapForCopyBits(_image), + GetPortBitMapForCopyBits(out_port), + &src_rect, &dest_rect, srcCopy, 0); + } + + int bar_width = min((int)(win_width * 0.6), 400); + int bar_height = min((int)(win_height * 0.1), 24); + int bar_x = (win_width - bar_width) / 2; + int bar_y = (win_height - bar_height * 2); + + int progress = bar_x + 1 + (int)((bar_width - 2) * _install_progress); + + Rect rbar = { bar_y, bar_x, bar_y + bar_height, bar_x + bar_width }; + Rect rneed = { bar_y + 1, progress + 1, bar_y + bar_height - 1, bar_x + bar_width - 1 }; + Rect rdone = { bar_y + 1, bar_x + 1, bar_y + bar_height - 1, progress }; + FrameRect(&rbar); + PaintRect(&rdone); + EraseRect(&rneed); + + TextFont(0); + TextFace(bold); + TextMode(srcOr); + TextSize(0); + + Point numer, denom; + FontInfo font_info; + StdTxMeas(_install_label.size(), _install_label.data(), &numer, &denom, &font_info); + + int text_width = TextWidth(_install_label.data(), 0, _install_label.size()); + int text_x = (win_width - text_width) / 2; + int text_y = bar_y - font_info.descent - 8; + + Rect rtext = { text_y - font_info.ascent - 2, text_x - 2, + text_y + font_info.descent + 2, text_x + text_width + 2 }; + EraseRect(&rtext); + + MoveTo(text_x, text_y); + DrawText(_install_label.data(), 0, _install_label.size()); + + if (portChanged) { + QDSwapPort(portSave, NULL); + } +} + + +#endif // __APPLE__ diff --git a/direct/src/plugin/p3dOsxSplashWindow.h b/direct/src/plugin/p3dOsxSplashWindow.h new file mode 100644 index 0000000000..6f8a732758 --- /dev/null +++ b/direct/src/plugin/p3dOsxSplashWindow.h @@ -0,0 +1,59 @@ +// Filename: p3dOsxSplashWindow.h +// Created by: drose (16Jul09) +// +//////////////////////////////////////////////////////////////////// +// +// 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 P3DOSXSPLASHWINDOW_H +#define P3DOSXSPLASHWINDOW_H + +#include "p3d_plugin_common.h" + +#ifdef __APPLE__ + +#include "p3dSplashWindow.h" + +#include + +//////////////////////////////////////////////////////////////////// +// Class : P3DOsxSplashWindow +// Description : This is the OSX implementation of the +// initial-download window. +//////////////////////////////////////////////////////////////////// +class P3DOsxSplashWindow : public P3DSplashWindow { +public: + P3DOsxSplashWindow(P3DInstance *inst); + virtual ~P3DOsxSplashWindow(); + + virtual void set_image_filename(const string &image_filename, + bool image_filename_temp); + virtual void set_install_label(const string &install_label); + virtual void set_install_progress(double install_progress); + + virtual void handle_event(P3D_event_data event); + +private: + void paint_window(); + +private: + GWorldPtr _image; + char *_image_data; + int _image_height, _image_width; + + string _install_label; + double _install_progress; +}; + +#include "p3dOsxSplashWindow.I" + +#endif // __APPLE__ + +#endif diff --git a/direct/src/plugin/p3dSplashWindow.cxx b/direct/src/plugin/p3dSplashWindow.cxx index 8a29f03bad..3a49e23ce3 100755 --- a/direct/src/plugin/p3dSplashWindow.cxx +++ b/direct/src/plugin/p3dSplashWindow.cxx @@ -110,6 +110,16 @@ void P3DSplashWindow:: set_install_progress(double install_progress) { } +//////////////////////////////////////////////////////////////////// +// Function: P3DSplashWindow::handle_event +// Access: Public, Virtual +// Description: Deals with the event callback from the OS window +// system. +//////////////////////////////////////////////////////////////////// +void P3DSplashWindow:: +handle_event(P3D_event_data event) { +} + //////////////////////////////////////////////////////////////////// // Function: P3DSplashWindow::read_image diff --git a/direct/src/plugin/p3dSplashWindow.h b/direct/src/plugin/p3dSplashWindow.h index a879b8394c..f0aac7c9e9 100755 --- a/direct/src/plugin/p3dSplashWindow.h +++ b/direct/src/plugin/p3dSplashWindow.h @@ -47,6 +47,8 @@ public: virtual void set_install_label(const string &install_label); virtual void set_install_progress(double install_progress); + virtual void handle_event(P3D_event_data event); + void setup_splash_image(); protected: diff --git a/direct/src/plugin/p3d_plugin.h b/direct/src/plugin/p3d_plugin.h index 906877364b..fb2e184524 100644 --- a/direct/src/plugin/p3d_plugin.h +++ b/direct/src/plugin/p3d_plugin.h @@ -630,6 +630,7 @@ typedef enum { P3D_RT_get_url, P3D_RT_post_url, P3D_RT_notify, + P3D_RT_refresh, } P3D_request_type; /* Structures corresponding to the request types in the above enum. */ @@ -673,6 +674,12 @@ typedef struct { const char *_message; } P3D_request_notify; +/* A refresh request. The instance would like to get a repaint event + on its own window. Only relevant for windowless plugins, e.g. on + OSX. */ +typedef struct { +} P3D_request_refresh; + /* This is the overall structure that represents a single request. It is returned by P3D_instance_get_request(). */ typedef struct { @@ -683,6 +690,7 @@ typedef struct { P3D_request_get_url _get_url; P3D_request_post_url _post_url; P3D_request_notify _notify; + P3D_request_refresh _refresh; } _request; } P3D_request; diff --git a/direct/src/plugin/p3d_plugin_composite1.cxx b/direct/src/plugin/p3d_plugin_composite1.cxx index 37c530006a..2f207e7378 100644 --- a/direct/src/plugin/p3d_plugin_composite1.cxx +++ b/direct/src/plugin/p3d_plugin_composite1.cxx @@ -13,6 +13,7 @@ #include "p3dMultifileReader.cxx" #include "p3dNoneObject.cxx" #include "p3dObject.cxx" +#include "p3dOsxSplashWindow.cxx" #include "p3dPackage.cxx" #include "p3dPythonObject.cxx" #include "p3dReferenceCount.cxx" diff --git a/direct/src/plugin_npapi/ppInstance.cxx b/direct/src/plugin_npapi/ppInstance.cxx index 381464865b..be0933ba18 100644 --- a/direct/src/plugin_npapi/ppInstance.cxx +++ b/direct/src/plugin_npapi/ppInstance.cxx @@ -52,6 +52,7 @@ PPInstance(NPMIMEType pluginType, NPP instance, uint16 mode, _started_instance_data = false; _got_instance_data = false; _got_window = false; + _python_window_open = false; } //////////////////////////////////////////////////////////////////// @@ -430,8 +431,23 @@ handle_request(P3D_request *request) { break; case P3D_RT_notify: - // We can ignore notifies, since these are handled by the core - // API. + // We mostly ignore notifies, since these are handled by the core + // API. But we do check for the "onwindowopen" notify, at which + // point we start spamming the refresh requests. + if (strcmp(request->_request._notify._message, "onwindowopen") == 0) { + _python_window_open = true; + if (_got_window) { + NPRect rect = { 0, 0, _window.height, _window.width }; + browser->invalidaterect(_npp_instance, &rect); + } + } + break; + + case P3D_RT_refresh: + if (_got_window) { + NPRect rect = { 0, 0, _window.height, _window.width }; + browser->invalidaterect(_npp_instance, &rect); + } break; default: @@ -472,8 +488,7 @@ handle_event(void *event) { // 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) { + if (_got_window && _python_window_open) { NPRect rect = { 0, 0, _window.height, _window.width }; browser->invalidaterect(_npp_instance, &rect); } @@ -612,11 +627,6 @@ variant_to_p3dobj(const NPVariant *variant) { //////////////////////////////////////////////////////////////////// void PPInstance:: request_ready(P3D_instance *instance) { - logfile - << "request_ready in " << instance - // << " thread = " << GetCurrentThreadId() - << "\n" << flush; - PPInstance *inst = (PPInstance *)(instance->_user_data); assert(inst != NULL); diff --git a/direct/src/plugin_npapi/ppInstance.h b/direct/src/plugin_npapi/ppInstance.h index 956dc78455..e4b413ba9c 100644 --- a/direct/src/plugin_npapi/ppInstance.h +++ b/direct/src/plugin_npapi/ppInstance.h @@ -104,6 +104,8 @@ private: LONG_PTR _orig_window_proc; #endif // _WIN32 + bool _python_window_open; + PPPandaObject *_script_object; P3D_instance *_p3d_inst; diff --git a/direct/src/plugin_npapi/startup.cxx b/direct/src/plugin_npapi/startup.cxx index 50a4af82f4..94ab3f7453 100644 --- a/direct/src/plugin_npapi/startup.cxx +++ b/direct/src/plugin_npapi/startup.cxx @@ -329,7 +329,7 @@ NPP_Print(NPP instance, NPPrint *platformPrint) { //////////////////////////////////////////////////////////////////// int16 NPP_HandleEvent(NPP instance, void *event) { - logfile << "HandleEvent\n" << flush; + // logfile << "HandleEvent\n" << flush; PPInstance *inst = (PPInstance *)(instance->pdata); assert(inst != NULL);