From bc0d953ab51ca2f912b99f7c13bfe75fee4d677e Mon Sep 17 00:00:00 2001 From: David Rose Date: Tue, 7 Jul 2009 22:33:07 +0000 Subject: [PATCH] fix windows crash; fix splash window drawing --- direct/src/plugin/p3dInstanceManager.cxx | 5 + direct/src/plugin/p3dPythonRun.cxx | 6 + direct/src/plugin/p3dSession.cxx | 4 + direct/src/plugin/p3dWinSplashWindow.cxx | 179 +++++++++++++++-------- direct/src/plugin/p3dWinSplashWindow.h | 6 + direct/src/plugin_npapi/ppInstance.cxx | 35 ++++- direct/src/plugin_npapi/startup.cxx | 10 +- 7 files changed, 173 insertions(+), 72 deletions(-) diff --git a/direct/src/plugin/p3dInstanceManager.cxx b/direct/src/plugin/p3dInstanceManager.cxx index e8fdd01f46..7449255ca7 100644 --- a/direct/src/plugin/p3dInstanceManager.cxx +++ b/direct/src/plugin/p3dInstanceManager.cxx @@ -17,6 +17,7 @@ #include "p3dSession.h" #include "p3dPackage.h" #include "p3d_plugin_config.h" +#include "p3dWinSplashWindow.h" #include "find_root_dir.h" #include "mkdir_complete.h" @@ -70,6 +71,10 @@ P3DInstanceManager:: assert(_instances.empty()); assert(_sessions.empty()); + +#ifdef _WIN32 + P3DWinSplashWindow::unregister_window_class(); +#endif } //////////////////////////////////////////////////////////////////// diff --git a/direct/src/plugin/p3dPythonRun.cxx b/direct/src/plugin/p3dPythonRun.cxx index e476eaa8e1..47c3e1ca1d 100755 --- a/direct/src/plugin/p3dPythonRun.cxx +++ b/direct/src/plugin/p3dPythonRun.cxx @@ -209,6 +209,7 @@ run_python() { //////////////////////////////////////////////////////////////////// void P3DPythonRun:: handle_command(TiXmlDocument *doc) { + nout << "received: " << *doc << "\n" << flush; TiXmlElement *xcommand = doc->FirstChildElement("command"); if (xcommand != NULL) { bool needs_response = false; @@ -267,6 +268,7 @@ handle_command(TiXmlDocument *doc) { xresponse->SetAttribute("response_id", want_response_id); doc.LinkEndChild(decl); doc.LinkEndChild(xresponse); + nout << "sent: " << doc << "\n" << flush; _pipe_write << doc << flush; } } @@ -413,6 +415,7 @@ handle_pyobj_command(TiXmlElement *xcommand, bool needs_response, } if (needs_response) { + nout << "sent: " << doc << "\n" << flush; _pipe_write << doc << flush; } } @@ -488,6 +491,7 @@ wait_script_response(int response_id) { // This is the response we were waiting for. _commands.erase(ci); RELEASE_LOCK(_commands_lock); + nout << "received: " << *doc << "\n" << flush; return doc; } } @@ -585,6 +589,7 @@ py_request_func(PyObject *args) { } xrequest->SetAttribute("message", message); + nout << "sent: " << doc << "\n" << flush; _pipe_write << doc << flush; } else if (strcmp(request_type, "script") == 0) { @@ -609,6 +614,7 @@ py_request_func(PyObject *args) { TiXmlElement *xvalue = pyobj_to_xml(value); xrequest->LinkEndChild(xvalue); + nout << "sent: " << doc << "\n" << flush; _pipe_write << doc << flush; } else { diff --git a/direct/src/plugin/p3dSession.cxx b/direct/src/plugin/p3dSession.cxx index 3237beb777..c246c08e61 100644 --- a/direct/src/plugin/p3dSession.cxx +++ b/direct/src/plugin/p3dSession.cxx @@ -85,6 +85,7 @@ P3DSession:: xcommand->SetAttribute("cmd", "exit"); doc.LinkEndChild(decl); doc.LinkEndChild(xcommand); + nout << "sent: " << doc << "\n" << flush; _pipe_write << doc << flush; // Also close the pipe, to help underscore the point. @@ -214,6 +215,7 @@ void P3DSession:: send_command(TiXmlDocument *command) { if (_p3dpython_running) { // Python is running. Send the command. + nout << "sent: " << *command << "\n" << flush; _pipe_write << *command << flush; delete command; } else { @@ -252,6 +254,7 @@ command_and_response(TiXmlDocument *command) { assert(xcommand != NULL); xcommand->SetAttribute("want_response_id", response_id); + nout << "sent: " << *command << "\n" << flush; _pipe_write << *command << flush; delete command; @@ -541,6 +544,7 @@ start_p3dpython() { // may have queued up. Commands::iterator ci; for (ci = _commands.begin(); ci != _commands.end(); ++ci) { + nout << "sent: " << *(*ci) << "\n" << flush; _pipe_write << *(*ci); delete (*ci); } diff --git a/direct/src/plugin/p3dWinSplashWindow.cxx b/direct/src/plugin/p3dWinSplashWindow.cxx index 65368c796d..1143e061b1 100755 --- a/direct/src/plugin/p3dWinSplashWindow.cxx +++ b/direct/src/plugin/p3dWinSplashWindow.cxx @@ -16,6 +16,8 @@ #ifdef _WIN32 +bool P3DWinSplashWindow::_registered_window_class = false; + //////////////////////////////////////////////////////////////////// // Function: P3DWinSplashWindow::Constructor // Access: Public @@ -132,7 +134,49 @@ set_install_progress(double install_progress) { } //////////////////////////////////////////////////////////////////// -// Function: P3DWinSplashWindow::start_thraed +// Function: P3DWinSplashWindow::register_window_class +// Access: Public, Static +// Description: Registers the window class for this window, if +// needed. +//////////////////////////////////////////////////////////////////// +void P3DWinSplashWindow:: +register_window_class() { + if (!_registered_window_class) { + HINSTANCE application = GetModuleHandle(NULL); + + WNDCLASS wc; + ZeroMemory(&wc, sizeof(WNDCLASS)); + wc.lpfnWndProc = st_window_proc; + wc.hInstance = application; + wc.lpszClassName = "panda3d_splash"; + + if (!RegisterClass(&wc)) { + nout << "Could not register window class panda3d_splash\n"; + } + _registered_window_class = true; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: P3DWinSplashWindow::unregister_window_class +// Access: Public, Static +// Description: Unregisters the window class for this window. It is +// necessary to do this before unloading the DLL. +//////////////////////////////////////////////////////////////////// +void P3DWinSplashWindow:: +unregister_window_class() { + if (_registered_window_class) { + HINSTANCE application = GetModuleHandle(NULL); + + if (!UnregisterClass("panda3d_splash", application)) { + nout << "Could not unregister window class panda3d_splash\n"; + } + _registered_window_class = false; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: P3DWinSplashWindow::start_thread // Access: Private // Description: Spawns the sub-thread. //////////////////////////////////////////////////////////////////// @@ -146,7 +190,7 @@ start_thread() { } //////////////////////////////////////////////////////////////////// -// Function: P3DWinSplashWindow::stop_thraed +// Function: P3DWinSplashWindow::stop_thread // Access: Private // Description: Terminates and joins the sub-thread. //////////////////////////////////////////////////////////////////// @@ -241,23 +285,8 @@ win_thread_run(LPVOID data) { //////////////////////////////////////////////////////////////////// void P3DWinSplashWindow:: make_window() { - WNDCLASS wc; - + register_window_class(); HINSTANCE application = GetModuleHandle(NULL); - - static bool registered_class = false; - if (!registered_class) { - ZeroMemory(&wc, sizeof(WNDCLASS)); - wc.lpfnWndProc = st_window_proc; - wc.hInstance = application; - wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); - wc.lpszClassName = "panda3d_splash"; - - if (!RegisterClass(&wc)) { - nout << "Could not register window class!\n"; - } - registered_class = true; - } int x = CW_USEDEFAULT; int y = CW_USEDEFAULT; @@ -482,6 +511,69 @@ close_window() { } } +//////////////////////////////////////////////////////////////////// +// Function: P3DWinSplashWindow::paint_window +// Access: Private +// Description: Paints the contents of the window into the indicated +// DC. +//////////////////////////////////////////////////////////////////// +void P3DWinSplashWindow:: +paint_window(HDC dc) { + RECT rect; + GetClientRect(_hwnd, &rect); + int win_width = rect.right - rect.left; + int win_height = rect.bottom - rect.top; + + if (_bitmap != NULL) { + // Paint the background splash image. + HDC mem_dc = CreateCompatibleDC(dc); + SelectObject(mem_dc, _bitmap); + + // Determine the relative size of bitmap and window. + int bm_width = _bitmap_width; + int bm_height = _bitmap_height; + + int win_cx = win_width / 2; + int win_cy = win_height / 2; + + if (bm_width <= win_width && bm_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 - bm_width / 2; + int p_y = win_cy - bm_height / 2; + + BitBlt(dc, p_x, p_y, bm_width, bm_height, + mem_dc, 0, 0, SRCCOPY); + + // Now don't paint over this in the below FillRect(). + ExcludeClipRect(dc, p_x, p_y, p_x + bm_width, p_y + bm_height); + + } else { + // The bitmap is larger than the window; scale it down. + double x_scale = (double)win_width / (double)bm_width; + double y_scale = (double)win_height / (double)bm_height; + double scale = min(x_scale, y_scale); + int sc_width = (int)(bm_width * scale); + int sc_height = (int)(bm_height * scale); + + int p_x = win_cx - sc_width / 2; + int p_y = win_cy - sc_height / 2; + StretchBlt(dc, p_x, p_y, sc_width, sc_height, + mem_dc, 0, 0, bm_width, bm_height, SRCCOPY); + + // Now don't paint over this in the below FillRect(). + ExcludeClipRect(dc, p_x, p_y, p_x + sc_width, p_y + sc_height); + } + + SelectObject(mem_dc, NULL); + DeleteDC(mem_dc); + } + + // Paint everything else the background color. + FillRect(dc, &rect, WHITE_BRUSH); +} + //////////////////////////////////////////////////////////////////// // Function: P3DWinSplashWindow::window_proc // Access: Private @@ -495,59 +587,20 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { break; case WM_SIZE: - InvalidateRect(hwnd, NULL, TRUE); + InvalidateRect(hwnd, NULL, FALSE); break; + case WM_ERASEBKGND: + return true; + case WM_PAINT: { PAINTSTRUCT ps; HDC dc = BeginPaint(hwnd, &ps); - if (_bitmap != NULL) { - // Paint the background splash image. - HDC mem_dc = CreateCompatibleDC(dc); - SelectObject(mem_dc, _bitmap); - - // Determine the relative size of bitmap and window. - RECT rect; - GetClientRect(hwnd, &rect); - int win_width = rect.right - rect.left; - int win_height = rect.bottom - rect.top; - int bm_width = _bitmap_width; - int bm_height = _bitmap_height; - - int win_cx = win_width / 2; - int win_cy = win_height / 2; - - if (bm_width <= win_width && bm_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 - bm_width / 2; - int p_y = win_cy - bm_height / 2; - - BitBlt(dc, p_x, p_y, bm_width, bm_height, - mem_dc, 0, 0, SRCCOPY); - - } else { - // The bitmap is larger than the window; scale it down. - double x_scale = (double)win_width / (double)bm_width; - double y_scale = (double)win_height / (double)bm_height; - double scale = min(x_scale, y_scale); - int sc_width = (int)(bm_width * scale); - int sc_height = (int)(bm_height * scale); - - int p_x = win_cx - sc_width / 2; - int p_y = win_cy - sc_height / 2; - StretchBlt(dc, p_x, p_y, sc_width, sc_height, - mem_dc, 0, 0, bm_width, bm_height, SRCCOPY); - } - - SelectObject(mem_dc, NULL); - DeleteDC(mem_dc); - } + paint_window(dc); EndPaint(hwnd, &ps); } - break; + return true; case WM_DRAWITEM: // Draw a text label placed within the window. diff --git a/direct/src/plugin/p3dWinSplashWindow.h b/direct/src/plugin/p3dWinSplashWindow.h index 2692d80a36..9836650dc4 100755 --- a/direct/src/plugin/p3dWinSplashWindow.h +++ b/direct/src/plugin/p3dWinSplashWindow.h @@ -39,6 +39,9 @@ public: virtual void set_install_label(const string &install_label); virtual void set_install_progress(double install_progress); + static void register_window_class(); + static void unregister_window_class(); + private: void start_thread(); void stop_thread(); @@ -55,6 +58,7 @@ private: bool image_filename_temp); void close_window(); + void paint_window(HDC dc); LONG window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam); static LONG WINAPI st_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam); @@ -79,6 +83,8 @@ private: int _bitmap_width, _bitmap_height; HWND _progress_bar; HWND _text_label; + + static bool _registered_window_class; }; #include "p3dWinSplashWindow.I" diff --git a/direct/src/plugin_npapi/ppInstance.cxx b/direct/src/plugin_npapi/ppInstance.cxx index 44882465e0..12ce218491 100644 --- a/direct/src/plugin_npapi/ppInstance.cxx +++ b/direct/src/plugin_npapi/ppInstance.cxx @@ -419,6 +419,10 @@ handle_request(P3D_request *request) { } break; + case P3D_RT_script: + // We're allowed to ignore this. + break; + default: // Some request types are not handled. logfile << "Unhandled request: " << request->_request_type << "\n"; @@ -762,24 +766,34 @@ void PPInstance:: send_window() { assert(_p3d_inst != NULL); + int x = _window.x; + int y = _window.y; + P3D_window_handle parent_window; #ifdef _WIN32 if (_window.type == NPWindowTypeWindow) { + // We have a "windowed" plugin. Parent our window to the one we + // were given. In this case, we should also reset the offset to + // (0, 0), since the window we were given is already placed in the + // right spot. parent_window._hwnd = (HWND)(_window.window); + x = 0; + y = 0; } else { - // Hmm, it's just a drawable; but we didn't ask for a windowless - // plugin. + // We have a "windowless" plugin. Parent our window directly to + // the browser window. parent_window._hwnd = 0; + HWND hwnd; + if (browser->getvalue(_npp_instance, NPNVnetscapeWindow, + &hwnd) == NPERR_NO_ERROR) { + parent_window._hwnd = hwnd; + } } #endif - // Actually, we set up the window starting at (0, 0), instead of - // whatever Mozilla tells us, because the window handle we get is a - // specially created window that is already aligned to where we want - // our window to be. P3D_instance_setup_window (_p3d_inst, P3D_WT_embedded, - 0, 0, _window.width, _window.height, + x, y, _window.width, _window.height, parent_window); } @@ -832,6 +846,13 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { } --recursion_protect; + switch (msg) { + case WM_ERASEBKGND: + // Eat the WM_ERASEBKGND message, so the browser's intervening + // window won't overdraw on top of our own window. + return true; + } + return DefWindowProc(hwnd, msg, wparam, lparam); } #endif // _WIN32 diff --git a/direct/src/plugin_npapi/startup.cxx b/direct/src/plugin_npapi/startup.cxx index 109b24d2eb..ef8fea971b 100644 --- a/direct/src/plugin_npapi/startup.cxx +++ b/direct/src/plugin_npapi/startup.cxx @@ -57,7 +57,7 @@ request_ready(P3D_instance *instance) { PPInstance *inst = (PPInstance *)(instance->_user_data); assert(inst != NULL); const NPWindow *win = inst->get_window(); - if (win != NULL) { + if (win != NULL && win->type == NPWindowTypeWindow) { PostMessage((HWND)(win->window), WM_USER, 0, 0); } @@ -161,6 +161,12 @@ NPP_New(NPMIMEType pluginType, NPP instance, uint16 mode, instance->pdata = new PPInstance(pluginType, instance, mode, argc, argn, argv, saved); + // To experiment with a "windowless" plugin, which really means we + // create our own window without an intervening window, try this. + // At the moment, there's a deadlock condition when we try it, but + // surely it can be solved. + // browser->setvalue(instance, NPPVpluginWindowBool, (void *)false); + return NPERR_NO_ERROR; } @@ -307,7 +313,7 @@ NPP_Print(NPP instance, NPPrint *platformPrint) { //////////////////////////////////////////////////////////////////// int16 NPP_HandleEvent(NPP instance, void *event) { - // logfile << "HandleEvent\n"; + logfile << "HandleEvent\n" << flush; // Here's a fine opportunity to check for new requests. PPInstance::handle_request_loop();